aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-01-14 21:19:43 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2014-01-14 21:19:43 +0100
commit59217ec9baa12b8a0dc26f8ff40877226ead167e (patch)
treed43f35e152de12bb8087e6695a5d64b235664d48
parent008db45dff789a65853c6e7acc29967650d60a0d (diff)
downloadopen-keychain-59217ec9baa12b8a0dc26f8ff40877226ead167e.tar.gz
open-keychain-59217ec9baa12b8a0dc26f8ff40877226ead167e.tar.bz2
open-keychain-59217ec9baa12b8a0dc26f8ff40877226ead167e.zip
fix some small layout bugs, add barcode scanner lib as source lib, fix qr code scanning issues
-rw-r--r--OpenPGP-Keychain/build.gradle3
-rw-r--r--OpenPGP-Keychain/libs/barcodescanner-android-integration-supportv4.jarbin8878 -> 0 bytes
-rw-r--r--OpenPGP-Keychain/project.properties1
-rw-r--r--OpenPGP-Keychain/res/layout/edit_key_activity.xml2
-rw-r--r--OpenPGP-Keychain/res/layout/edit_key_key_item.xml2
-rw-r--r--OpenPGP-Keychain/res/layout/import_keys_qr_code_fragment.xml12
-rw-r--r--OpenPGP-Keychain/res/values/strings.xml11
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java15
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java42
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/ExpandableListFragment.java530
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java2
-rw-r--r--README.md20
-rw-r--r--libraries/zxing-android-integration/.gitignore30
-rw-r--r--libraries/zxing-android-integration/AndroidManifest.xml11
-rw-r--r--libraries/zxing-android-integration/build.gradle14
-rw-r--r--libraries/zxing-android-integration/project.properties15
-rw-r--r--libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentIntegrator.java434
-rw-r--r--libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentResult.java95
-rw-r--r--libraries/zxing/.gitignore30
-rw-r--r--settings.gradle3
20 files changed, 703 insertions, 569 deletions
diff --git a/OpenPGP-Keychain/build.gradle b/OpenPGP-Keychain/build.gradle
index 0fffd1fd3..566559a00 100644
--- a/OpenPGP-Keychain/build.gradle
+++ b/OpenPGP-Keychain/build.gradle
@@ -24,8 +24,9 @@ dependencies {
compile project(':libraries:ActionBarSherlock')
compile project(':libraries:HtmlTextView')
compile project(':libraries:StickyListHeaders:library')
- compile project(':libraries:zxing')
compile project(':libraries:AndroidBootstrap')
+ compile project(':libraries:zxing')
+ compile project(':libraries:zxing-android-integration')
}
android {
diff --git a/OpenPGP-Keychain/libs/barcodescanner-android-integration-supportv4.jar b/OpenPGP-Keychain/libs/barcodescanner-android-integration-supportv4.jar
deleted file mode 100644
index 4a7f1a39c..000000000
--- a/OpenPGP-Keychain/libs/barcodescanner-android-integration-supportv4.jar
+++ /dev/null
Binary files differ
diff --git a/OpenPGP-Keychain/project.properties b/OpenPGP-Keychain/project.properties
index 76caac668..96546d84f 100644
--- a/OpenPGP-Keychain/project.properties
+++ b/OpenPGP-Keychain/project.properties
@@ -14,3 +14,4 @@ android.library.reference.2=../libraries/HtmlTextView
android.library.reference.3=../libraries/StickyListHeaders/library
android.library.reference.4=../libraries/zxing
android.library.reference.5=../libraries/AndroidBootstrap
+android.library.reference.6=../libraries/zxing-android-integration
diff --git a/OpenPGP-Keychain/res/layout/edit_key_activity.xml b/OpenPGP-Keychain/res/layout/edit_key_activity.xml
index f8597b0df..351aec512 100644
--- a/OpenPGP-Keychain/res/layout/edit_key_activity.xml
+++ b/OpenPGP-Keychain/res/layout/edit_key_activity.xml
@@ -45,7 +45,7 @@
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/edit_key_btn_change_pass_phrase"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="60dp"
android:padding="4dp"
android:text="@string/btn_set_passphrase"
bootstrapbutton:bb_icon_left="fa-pencil"
diff --git a/OpenPGP-Keychain/res/layout/edit_key_key_item.xml b/OpenPGP-Keychain/res/layout/edit_key_key_item.xml
index 11bce64ee..ad6bd6779 100644
--- a/OpenPGP-Keychain/res/layout/edit_key_key_item.xml
+++ b/OpenPGP-Keychain/res/layout/edit_key_key_item.xml
@@ -82,7 +82,7 @@
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/expiry"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="60dp"
android:text="@string/none"
bootstrapbutton:bb_type="default" />
</TableRow>
diff --git a/OpenPGP-Keychain/res/layout/import_keys_qr_code_fragment.xml b/OpenPGP-Keychain/res/layout/import_keys_qr_code_fragment.xml
index f3c09a41d..5229e7cf5 100644
--- a/OpenPGP-Keychain/res/layout/import_keys_qr_code_fragment.xml
+++ b/OpenPGP-Keychain/res/layout/import_keys_qr_code_fragment.xml
@@ -10,7 +10,7 @@
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_margin="10dp"
- android:text="@string/menu_import_from_qr_code"
+ android:text="@string/import_qr_scan_button"
bootstrapbutton:bb_icon_left="fa-barcode"
bootstrapbutton:bb_size="default"
bootstrapbutton:bb_type="default" />
@@ -18,13 +18,19 @@
<TextView
android:id="@+id/import_qrcode_text"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:visibility="gone" />
<ProgressBar
android:id="@+id/import_qrcode_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:progress="0" />
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:progress="0"
+ android:visibility="gone" />
</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/res/values/strings.xml b/OpenPGP-Keychain/res/values/strings.xml
index 72709965a..746a13015 100644
--- a/OpenPGP-Keychain/res/values/strings.xml
+++ b/OpenPGP-Keychain/res/values/strings.xml
@@ -322,9 +322,16 @@
<string name="import_import">Import selected keys</string>
<string name="import_sign_and_upload">Import, Sign, and upload selected keys</string>
<string name="import_from_clipboard">Import from Clipboard</string>
- <string name="import_qr_code_missing">Missing QR Codes: %1$s</string>
+
+ <plurals name="import_qr_code_missing">
+ <item quantity="one">Missing QR Code with ID %1$s</item>
+ <item quantity="other">Missing QR Codes with IDs %1$s</item>
+ </plurals>
+
+ <string name="import_qr_code_start_with_one">Please start with QR Code with ID 1</string>
<string name="import_qr_code_wrong">QR Code malformed! Please try again!</string>
<string name="import_qr_code_finished">QR Code scanning finished!</string>
+ <string name="import_qr_scan_button">Scan QR Code with \'Barcode Scanner\'</string>
<!-- Intent labels -->
<string name="intent_decrypt_file">OpenPGP: Decrypt File</string>
@@ -354,7 +361,7 @@
<!-- Share -->
<string name="share_qr_code_dialog_start">Go through all QR Codes using \'Next\', and scan them one by one.</string>
- <string name="share_qr_code_dialog_progress">QR Code %1$d of %2$d</string>
+ <string name="share_qr_code_dialog_progress">QR Code with ID %1$d of %2$d</string>
<string name="share_nfc_dialog">Share with NFC</string>
<!-- Key list -->
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 7d8f4154f..00a648355 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -76,6 +76,8 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi
OnNavigationListener mOnNavigationListener;
String[] mNavigationStrings;
+ Fragment mCurrentFragment;
+
BootstrapButton mImportButton;
BootstrapButton mImportSignUploadButton;
@@ -226,12 +228,12 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi
}
private void loadFragment(Class<?> clss, Bundle args, String tag) {
- Fragment fragment = Fragment.instantiate(this, clss.getName(), args);
+ mCurrentFragment = Fragment.instantiate(this, clss.getName(), args);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment container with this fragment
// and give the fragment a tag name equal to the string at the position selected
- ft.replace(R.id.import_navigation_fragment, fragment, tag);
+ ft.replace(R.id.import_navigation_fragment, mCurrentFragment, tag);
// Apply changes
ft.commit();
}
@@ -298,6 +300,15 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi
// }
// }
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // required for qr code scanning
+ if (mCurrentFragment != null) {
+ mCurrentFragment.onActivityResult(requestCode, resultCode, data);
+ }
+ // super.onActivityResult(requestCode, resultCode, data);
+ }
+
/**
* Import keys with mImportData
*/
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
index f9ead3a94..bdedbec0a 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
@@ -35,7 +35,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
-import com.google.zxing.integration.android.IntentIntegratorSupportV4;
+import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
public class ImportKeysQrCodeFragment extends Fragment {
@@ -45,7 +45,7 @@ public class ImportKeysQrCodeFragment extends Fragment {
private TextView mText;
private ProgressBar mProgress;
- private String[] scannedContent;
+ private String[] mScannedContent;
/**
* Creates new instance of this fragment
@@ -75,7 +75,7 @@ public class ImportKeysQrCodeFragment extends Fragment {
@Override
public void onClick(View v) {
// scan using xzing's Barcode Scanner
- new IntentIntegratorSupportV4(ImportKeysQrCodeFragment.this).initiateScan();
+ new IntentIntegrator(getActivity()).initiateScan();
}
});
@@ -92,9 +92,9 @@ public class ImportKeysQrCodeFragment extends Fragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
- case IntentIntegratorSupportV4.REQUEST_CODE: {
- IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
- resultCode, data);
+ case IntentIntegrator.REQUEST_CODE: {
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode,
+ data);
if (scanResult != null && scanResult.getFormatName() != null) {
Log.d(Constants.TAG, scanResult.getContents());
@@ -117,36 +117,50 @@ public class ImportKeysQrCodeFragment extends Fragment {
// first qr code -> setup
if (counter == 0) {
- scannedContent = new String[size];
+ mScannedContent = new String[size];
mProgress.setMax(size);
+ mProgress.setVisibility(View.VISIBLE);
+ mText.setVisibility(View.VISIBLE);
+ }
+
+ if (mScannedContent == null || counter > mScannedContent.length) {
+ Toast.makeText(getActivity(), R.string.import_qr_code_start_with_one,
+ Toast.LENGTH_LONG).show();
+ return;
}
// save scanned content
- scannedContent[counter] = content;
+ mScannedContent[counter] = content;
// get missing numbers
ArrayList<Integer> missing = new ArrayList<Integer>();
- for (int i = 0; i < scannedContent.length; i++) {
- if (scannedContent[i] == null) {
+ for (int i = 0; i < mScannedContent.length; i++) {
+ if (mScannedContent[i] == null) {
missing.add(i);
}
}
// update progress and text
- mProgress.setProgress(scannedContent.length - missing.size());
+ int alreadyScanned = mScannedContent.length - missing.size();
+ mProgress.setProgress(alreadyScanned);
+
String missingString = "";
for (int m : missing) {
- if (!missingString.equals(""))
+ if (!missingString.equals("")) {
missingString += ", ";
+ }
missingString += String.valueOf(m + 1);
}
- mText.setText(getString(R.string.import_qr_code_missing, missingString));
+
+ String missingText = getResources().getQuantityString(
+ R.plurals.import_qr_code_missing, missing.size(), missingString);
+ mText.setText(missingText);
// finished!
if (missing.size() == 0) {
mText.setText(R.string.import_qr_code_finished);
String result = "";
- for (String in : scannedContent) {
+ for (String in : mScannedContent) {
result += in;
}
mImportActivity.loadCallback(result.getBytes(), null);
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/ExpandableListFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/ExpandableListFragment.java
deleted file mode 100644
index 54022342f..000000000
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/ExpandableListFragment.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.sufficientlysecure.keychain.ui.widget;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v4.app.Fragment;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnCreateContextMenuListener;
-import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.widget.AdapterView;
-import android.widget.ExpandableListAdapter;
-import android.widget.ExpandableListView;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.ListAdapter;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-/**
- * @author Khoa Tran
- *
- * @see android.support.v4.app.ListFragment
- * @see android.app.ExpandableListActivity
- *
- * ExpandableListFragment for Android < 3.0
- *
- * from
- * http://stackoverflow.com/questions/6051050/expandablelistfragment-with-loadermanager-for-
- * compatibility-package
- *
- */
-public class ExpandableListFragment extends Fragment implements OnCreateContextMenuListener,
- ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
- ExpandableListView.OnGroupExpandListener {
-
- static final int INTERNAL_EMPTY_ID = 0x00ff0001;
- static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002;
- static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;
-
- final private Handler mHandler = new Handler();
-
- final private Runnable mRequestFocus = new Runnable() {
- public void run() {
- mExpandableList.focusableViewAvailable(mExpandableList);
- }
- };
-
- final private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
- onListItemClick((ExpandableListView) parent, v, position, id);
- }
- };
-
- ExpandableListAdapter mAdapter;
- ExpandableListView mExpandableList;
- boolean mFinishedStart = false;
- View mEmptyView;
- TextView mStandardEmptyView;
- View mProgressContainer;
- View mExpandableListContainer;
- CharSequence mEmptyText;
- boolean mExpandableListShown;
-
- public ExpandableListFragment() {
- }
-
- /**
- * Provide default implementation to return a simple list view. Subclasses can override to
- * replace with their own layout. If doing so, the returned view hierarchy <em>must</em> have a
- * ListView whose id is {@link android.R.id#list android.R.id.list} and can optionally have a
- * sibling view id {@link android.R.id#empty android.R.id.empty} that is to be shown when the
- * list is empty.
- *
- * <p>
- * If you are overriding this method with your own custom content, consider including the
- * standard layout {@link android.R.layout#list_content} in your layout file, so that you
- * continue to retain all of the standard behavior of ListFragment. In particular, this is
- * currently the only way to have the built-in indeterminant progress state be shown.
- */
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- final Context context = getActivity();
-
- FrameLayout root = new FrameLayout(context);
-
- // ------------------------------------------------------------------
-
- LinearLayout pframe = new LinearLayout(context);
- pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);
- pframe.setOrientation(LinearLayout.VERTICAL);
- pframe.setVisibility(View.GONE);
- pframe.setGravity(Gravity.CENTER);
-
- ProgressBar progress = new ProgressBar(context, null, android.R.attr.progressBarStyleLarge);
- pframe.addView(progress, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
-
- root.addView(pframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- // ------------------------------------------------------------------
-
- FrameLayout lframe = new FrameLayout(context);
- lframe.setId(INTERNAL_LIST_CONTAINER_ID);
-
- TextView tv = new TextView(getActivity());
- tv.setId(INTERNAL_EMPTY_ID);
- tv.setGravity(Gravity.CENTER);
- lframe.addView(tv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- ExpandableListView lv = new ExpandableListView(getActivity());
- lv.setId(android.R.id.list);
- lv.setDrawSelectorOnTop(false);
- lframe.addView(lv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- root.addView(lframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- // ------------------------------------------------------------------
-
- root.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- return root;
- }
-
- /**
- * Attach to list view once the view hierarchy has been created.
- */
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- ensureList();
- }
-
- /**
- * Detach from list view.
- */
- @Override
- public void onDestroyView() {
- mHandler.removeCallbacks(mRequestFocus);
- mExpandableList = null;
- mExpandableListShown = false;
- mEmptyView = mProgressContainer = mExpandableListContainer = null;
- mStandardEmptyView = null;
- super.onDestroyView();
- }
-
- /**
- * This method will be called when an item in the list is selected. Subclasses should override.
- * Subclasses can call getListView().getItemAtPosition(position) if they need to access the data
- * associated with the selected item.
- *
- * @param l
- * The ListView where the click happened
- * @param v
- * The view that was clicked within the ListView
- * @param position
- * The position of the view in the list
- * @param id
- * The row id of the item that was clicked
- */
- public void onListItemClick(ExpandableListView l, View v, int position, long id) {
- }
-
- /**
- * Provide the cursor for the list view.
- */
- public void setListAdapter(ExpandableListAdapter adapter) {
- boolean hadAdapter = mAdapter != null;
- mAdapter = adapter;
- if (mExpandableList != null) {
- mExpandableList.setAdapter(adapter);
- if (!mExpandableListShown && !hadAdapter) {
- // The list was hidden, and previously didn't have an
- // adapter. It is now time to show it.
- setListShown(true, getView().getWindowToken() != null);
- }
- }
- }
-
- /**
- * Set the currently selected list item to the specified position with the adapter's data
- *
- * @param position
- */
- public void setSelection(int position) {
- ensureList();
- mExpandableList.setSelection(position);
- }
-
- /**
- * Get the position of the currently selected list item.
- */
- public int getSelectedItemPosition() {
- ensureList();
- return mExpandableList.getSelectedItemPosition();
- }
-
- /**
- * Get the cursor row ID of the currently selected list item.
- */
- public long getSelectedItemId() {
- ensureList();
- return mExpandableList.getSelectedItemId();
- }
-
- /**
- * Get the activity's list view widget.
- */
- public ExpandableListView getListView() {
- ensureList();
- return mExpandableList;
- }
-
- /**
- * The default content for a ListFragment has a TextView that can be shown when the list is
- * empty. If you would like to have it shown, call this method to supply the text it should use.
- */
- public void setEmptyText(CharSequence text) {
- ensureList();
- if (mStandardEmptyView == null) {
- throw new IllegalStateException("Can't be used with a custom content view");
- }
- mStandardEmptyView.setText(text);
- if (mEmptyText == null) {
- mExpandableList.setEmptyView(mStandardEmptyView);
- }
- mEmptyText = text;
- }
-
- /**
- * Control whether the list is being displayed. You can make it not displayed if you are waiting
- * for the initial data to show in it. During this time an indeterminant progress indicator will
- * be shown instead.
- *
- * <p>
- * Applications do not normally need to use this themselves. The default behavior of
- * ListFragment is to start with the list not being shown, only showing it once an adapter is
- * given with {@link #setListAdapter(ListAdapter)}. If the list at that point had not been
- * shown, when it does get shown it will be do without the user ever seeing the hidden state.
- *
- * @param shown
- * If true, the list view is shown; if false, the progress indicator. The initial
- * value is true.
- */
- public void setListShown(boolean shown) {
- setListShown(shown, true);
- }
-
- /**
- * Like {@link #setListShown(boolean)}, but no animation is used when transitioning from the
- * previous state.
- */
- public void setListShownNoAnimation(boolean shown) {
- setListShown(shown, false);
- }
-
- /**
- * Control whether the list is being displayed. You can make it not displayed if you are waiting
- * for the initial data to show in it. During this time an indeterminant progress indicator will
- * be shown instead.
- *
- * @param shown
- * If true, the list view is shown; if false, the progress indicator. The initial
- * value is true.
- * @param animate
- * If true, an animation will be used to transition to the new state.
- */
- private void setListShown(boolean shown, boolean animate) {
- ensureList();
- if (mProgressContainer == null) {
- throw new IllegalStateException("Can't be used with a custom content view");
- }
- if (mExpandableListShown == shown) {
- return;
- }
- mExpandableListShown = shown;
- if (shown) {
- if (animate) {
- mProgressContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(),
- android.R.anim.fade_out));
- mExpandableListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(),
- android.R.anim.fade_in));
- } else {
- mProgressContainer.clearAnimation();
- mExpandableListContainer.clearAnimation();
- }
- mProgressContainer.setVisibility(View.GONE);
- mExpandableListContainer.setVisibility(View.VISIBLE);
- } else {
- if (animate) {
- mProgressContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(),
- android.R.anim.fade_in));
- mExpandableListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(),
- android.R.anim.fade_out));
- } else {
- mProgressContainer.clearAnimation();
- mExpandableListContainer.clearAnimation();
- }
- mProgressContainer.setVisibility(View.VISIBLE);
- mExpandableListContainer.setVisibility(View.GONE);
- }
- }
-
- /**
- * Get the ListAdapter associated with this activity's ListView.
- */
- public ExpandableListAdapter getListAdapter() {
- return mAdapter;
- }
-
- private void ensureList() {
- if (mExpandableList != null) {
- return;
- }
- View root = getView();
- if (root == null) {
- throw new IllegalStateException("Content view not yet created");
- }
- if (root instanceof ExpandableListView) {
- mExpandableList = (ExpandableListView) root;
- } else {
- mStandardEmptyView = (TextView) root.findViewById(INTERNAL_EMPTY_ID);
- if (mStandardEmptyView == null) {
- mEmptyView = root.findViewById(android.R.id.empty);
- } else {
- mStandardEmptyView.setVisibility(View.GONE);
- }
- mProgressContainer = root.findViewById(INTERNAL_PROGRESS_CONTAINER_ID);
- mExpandableListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID);
- View rawExpandableListView = root.findViewById(android.R.id.list);
- if (!(rawExpandableListView instanceof ExpandableListView)) {
- if (rawExpandableListView == null) {
- throw new RuntimeException(
- "Your content must have a ListView whose id attribute is "
- + "'android.R.id.list'");
- }
- throw new RuntimeException(
- "Content has view with id attribute 'android.R.id.list' "
- + "that is not a ListView class");
- }
- mExpandableList = (ExpandableListView) rawExpandableListView;
- if (mEmptyView != null) {
- mExpandableList.setEmptyView(mEmptyView);
- } else if (mEmptyText != null) {
- mStandardEmptyView.setText(mEmptyText);
- mExpandableList.setEmptyView(mStandardEmptyView);
- }
- }
- mExpandableListShown = true;
- mExpandableList.setOnItemClickListener(mOnClickListener);
- if (mAdapter != null) {
- ExpandableListAdapter adapter = mAdapter;
- mAdapter = null;
- setListAdapter(adapter);
- } else {
- // We are starting without an adapter, so assume we won't
- // have our data right away and start with the progress indicator.
- if (mProgressContainer != null) {
- setListShown(false, false);
- }
- }
- mHandler.post(mRequestFocus);
- }
-
- /**
- * Override this to populate the context menu when an item is long pressed. menuInfo will
- * contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo} whose
- * packedPosition is a packed position that should be used with
- * {@link ExpandableListView#getPackedPositionType(long)} and the other similar methods.
- * <p>
- * {@inheritDoc}
- */
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
- }
-
- /**
- * Override this for receiving callbacks when a child has been clicked.
- * <p>
- * {@inheritDoc}
- */
- public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
- int childPosition, long id) {
- return false;
- }
-
- /**
- * Override this for receiving callbacks when a group has been collapsed.
- */
- public void onGroupCollapse(int groupPosition) {
- }
-
- /**
- * Override this for receiving callbacks when a group has been expanded.
- */
- public void onGroupExpand(int groupPosition) {
- }
-
- // /**
- // * Ensures the expandable list view has been created before Activity restores all
- // * of the view states.
- // *
- // *@see Activity#onRestoreInstanceState(Bundle)
- // */
- // @Override
- // protected void onRestoreInstanceState(Bundle state) {
- // ensureList();
- // super.onRestoreInstanceState(state);
- // }
-
- /**
- * Updates the screen state (current list and other views) when the content changes.
- *
- * @see Activity#onContentChanged()
- */
-
- public void onContentChanged() {
- // super.onContentChanged();
- View emptyView = getView().findViewById(android.R.id.empty);
- mExpandableList = (ExpandableListView) getView().findViewById(android.R.id.list);
- if (mExpandableList == null) {
- throw new RuntimeException(
- "Your content must have a ExpandableListView whose id attribute is "
- + "'android.R.id.list'");
- }
- if (emptyView != null) {
- mExpandableList.setEmptyView(emptyView);
- }
- mExpandableList.setOnChildClickListener(this);
- mExpandableList.setOnGroupExpandListener(this);
- mExpandableList.setOnGroupCollapseListener(this);
-
- if (mFinishedStart) {
- setListAdapter(mAdapter);
- }
- mFinishedStart = true;
- }
-
- /**
- * Get the activity's expandable list view widget. This can be used to get the selection, set
- * the selection, and many other useful functions.
- *
- * @see ExpandableListView
- */
- public ExpandableListView getExpandableListView() {
- ensureList();
- return mExpandableList;
- }
-
- /**
- * Get the ExpandableListAdapter associated with this activity's ExpandableListView.
- */
- public ExpandableListAdapter getExpandableListAdapter() {
- return mAdapter;
- }
-
- /**
- * Gets the ID of the currently selected group or child.
- *
- * @return The ID of the currently selected group or child.
- */
- public long getSelectedId() {
- return mExpandableList.getSelectedId();
- }
-
- /**
- * Gets the position (in packed position representation) of the currently selected group or
- * child. Use {@link ExpandableListView#getPackedPositionType},
- * {@link ExpandableListView#getPackedPositionGroup}, and
- * {@link ExpandableListView#getPackedPositionChild} to unpack the returned packed position.
- *
- * @return A packed position representation containing the currently selected group or child's
- * position and type.
- */
- public long getSelectedPosition() {
- return mExpandableList.getSelectedPosition();
- }
-
- /**
- * Sets the selection to the specified child. If the child is in a collapsed group, the group
- * will only be expanded and child subsequently selected if shouldExpandGroup is set to true,
- * otherwise the method will return false.
- *
- * @param groupPosition
- * The position of the group that contains the child.
- * @param childPosition
- * The position of the child within the group.
- * @param shouldExpandGroup
- * Whether the child's group should be expanded if it is collapsed.
- * @return Whether the selection was successfully set on the child.
- */
- public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
- return mExpandableList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
- }
-
- /**
- * Sets the selection to the specified group.
- *
- * @param groupPosition
- * The position of the group that should be selected.
- */
- public void setSelectedGroup(int groupPosition) {
- mExpandableList.setSelectedGroup(groupPosition);
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java
index b33dbe4c5..1f9605fb1 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/widget/SectionView.java
@@ -190,7 +190,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
keySizeAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
keySize.setAdapter(keySizeAdapter);
- keySize.setSelection(2); // Default to 2048 for the key length
+ keySize.setSelection(3); // Default to 4096 for the key length
dialog.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int id) {
diff --git a/README.md b/README.md
index df2e72850..ee97fe0d1 100644
--- a/README.md
+++ b/README.md
@@ -26,12 +26,8 @@ I am happy about every code contribution and appreciate your effort to help us d
Android Studio is currently not supported or recommended!
1. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/ActionBarSherlock"
-2. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/HtmlTextView"
-3. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/StickyListHeaders/library"
-4. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/zxing"
-5. File -> Import -> Android -> Existing Android Code Into Workspace, choose "libraries/AndroidBootstrap"
-6. File -> Import -> Android -> Existing Android Code Into Workspace, choose "OpenPGP-Keychain"
-7. OpenPGP-Kechain can now be build
+2. Repeat step 1 with "libraries/HtmlTextView", "libraries/StickyListHeaders/library", "libraries/AndroidBootstrap", "libraries/zxing", "libraries/zxing-android-integration", "OpenPGP-Keychain"
+3. Now all required source files are available in Eclipse
# Keychain API
@@ -109,18 +105,16 @@ TODO
# Libraries
-## Build Barcode Scanner Integration
+## ZXing Barcode Scanner Android Integration
-1. Checkout their SVN (see http://code.google.com/p/zxing/source/checkout)
-2. Change android-home variable in "build.properties" in the main directory to point to your Android SDK
-3. Change directory to android-integration
-4. Build using ``ant build``
-5. We use "android-integration-supportv4.jar"
+Classes can be found under "libraries/zxing-android-integration/".
-On error see: http://code.google.com/p/zxing/issues/detail?id=1207
+1. Checkout their SVN (see http://code.google.com/p/zxing/source/checkout)
+2. Copy all classes from their android-integration folder to our library folder
## ZXing
+Classes can be found under "libraries/zxing/".
ZXing classes were extracted from the ZXing library (http://code.google.com/p/zxing/).
Only classes related to QR Code generation are utilized.
diff --git a/libraries/zxing-android-integration/.gitignore b/libraries/zxing-android-integration/.gitignore
new file mode 100644
index 000000000..71c11b159
--- /dev/null
+++ b/libraries/zxing-android-integration/.gitignore
@@ -0,0 +1,30 @@
+#Android specific
+bin
+gen
+obj
+libs/armeabi
+lint.xml
+local.properties
+release.properties
+ant.properties
+*.class
+*.apk
+
+#Gradle
+.gradle
+build
+gradle.properties
+
+#Maven
+target
+pom.xml.*
+
+#Eclipse
+.project
+.classpath
+.settings
+.metadata
+
+#IntelliJ IDEA
+.idea
+*.iml
diff --git a/libraries/zxing-android-integration/AndroidManifest.xml b/libraries/zxing-android-integration/AndroidManifest.xml
new file mode 100644
index 000000000..c3a6ba464
--- /dev/null
+++ b/libraries/zxing-android-integration/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.zxing.android"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="8"
+ android:targetSdkVersion="19" />
+
+</manifest> \ No newline at end of file
diff --git a/libraries/zxing-android-integration/build.gradle b/libraries/zxing-android-integration/build.gradle
new file mode 100644
index 000000000..21050fc98
--- /dev/null
+++ b/libraries/zxing-android-integration/build.gradle
@@ -0,0 +1,14 @@
+apply plugin: 'android-library'
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion '19.0.0'
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ res.srcDirs = ['res']
+ }
+ }
+}
diff --git a/libraries/zxing-android-integration/project.properties b/libraries/zxing-android-integration/project.properties
new file mode 100644
index 000000000..91d2b0246
--- /dev/null
+++ b/libraries/zxing-android-integration/project.properties
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-19
+android.library=true
diff --git a/libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentIntegrator.java b/libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentIntegrator.java
new file mode 100644
index 000000000..4980e9e7e
--- /dev/null
+++ b/libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentIntegrator.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright 2009 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing.integration.android;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * <p>A utility class which helps ease integration with Barcode Scanner via {@link Intent}s. This is a simple
+ * way to invoke barcode scanning and receive the result, without any need to integrate, modify, or learn the
+ * project's source code.</p>
+ *
+ * <h2>Initiating a barcode scan</h2>
+ *
+ * <p>To integrate, create an instance of {@code IntentIntegrator} and call {@link #initiateScan()} and wait
+ * for the result in your app.</p>
+ *
+ * <p>It does require that the Barcode Scanner (or work-alike) application is installed. The
+ * {@link #initiateScan()} method will prompt the user to download the application, if needed.</p>
+ *
+ * <p>There are a few steps to using this integration. First, your {@link Activity} must implement
+ * the method {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:</p>
+ *
+ * <pre>{@code
+ * public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ * IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
+ * if (scanResult != null) {
+ * // handle scan result
+ * }
+ * // else continue with any other code you need in the method
+ * ...
+ * }
+ * }</pre>
+ *
+ * <p>This is where you will handle a scan result.</p>
+ *
+ * <p>Second, just call this in response to a user action somewhere to begin the scan process:</p>
+ *
+ * <pre>{@code
+ * IntentIntegrator integrator = new IntentIntegrator(yourActivity);
+ * integrator.initiateScan();
+ * }</pre>
+ *
+ * <p>Note that {@link #initiateScan()} returns an {@link AlertDialog} which is non-null if the
+ * user was prompted to download the application. This lets the calling app potentially manage the dialog.
+ * In particular, ideally, the app dismisses the dialog if it's still active in its {@link Activity#onPause()}
+ * method.</p>
+ *
+ * <p>You can use {@link #setTitle(String)} to customize the title of this download prompt dialog (or, use
+ * {@link #setTitleByID(int)} to set the title by string resource ID.) Likewise, the prompt message, and
+ * yes/no button labels can be changed.</p>
+ *
+ * <p>Finally, you can use {@link #addExtra(String, Object)} to add more parameters to the Intent used
+ * to invoke the scanner. This can be used to set additional options not directly exposed by this
+ * simplified API.</p>
+ *
+ * <p>By default, this will only allow applications that are known to respond to this intent correctly
+ * do so. The apps that are allowed to response can be set with {@link #setTargetApplications(List)}.
+ * For example, set to {@link #TARGET_BARCODE_SCANNER_ONLY} to only target the Barcode Scanner app itself.</p>
+ *
+ * <h2>Sharing text via barcode</h2>
+ *
+ * <p>To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(CharSequence)}.</p>
+ *
+ * <p>Some code, particularly download integration, was contributed from the Anobiit application.</p>
+ *
+ * <h2>Enabling experimental barcode formats</h2>
+ *
+ * <p>Some formats are not enabled by default even when scanning with {@link #ALL_CODE_TYPES}, such as
+ * PDF417. Use {@link #initiateScan(java.util.Collection)} with
+ * a collection containing the names of formats to scan for explicitly, like "PDF_417", to use such
+ * formats.</p>
+ *
+ * @author Sean Owen
+ * @author Fred Lin
+ * @author Isaac Potoczny-Jones
+ * @author Brad Drehmer
+ * @author gcstang
+ */
+public class IntentIntegrator {
+
+ public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits
+ private static final String TAG = IntentIntegrator.class.getSimpleName();
+
+ public static final String DEFAULT_TITLE = "Install Barcode Scanner?";
+ public static final String DEFAULT_MESSAGE =
+ "This application requires Barcode Scanner. Would you like to install it?";
+ public static final String DEFAULT_YES = "Yes";
+ public static final String DEFAULT_NO = "No";
+
+ private static final String BS_PACKAGE = "com.google.zxing.client.android";
+ private static final String BSPLUS_PACKAGE = "com.srowen.bs.android";
+
+ // supported barcode formats
+ public static final Collection<String> PRODUCT_CODE_TYPES = list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "RSS_14");
+ public static final Collection<String> ONE_D_CODE_TYPES =
+ list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "CODE_39", "CODE_93", "CODE_128",
+ "ITF", "RSS_14", "RSS_EXPANDED");
+ public static final Collection<String> QR_CODE_TYPES = Collections.singleton("QR_CODE");
+ public static final Collection<String> DATA_MATRIX_TYPES = Collections.singleton("DATA_MATRIX");
+
+ public static final Collection<String> ALL_CODE_TYPES = null;
+
+ public static final List<String> TARGET_BARCODE_SCANNER_ONLY = Collections.singletonList(BS_PACKAGE);
+ public static final List<String> TARGET_ALL_KNOWN = list(
+ BSPLUS_PACKAGE, // Barcode Scanner+
+ BSPLUS_PACKAGE + ".simple", // Barcode Scanner+ Simple
+ BS_PACKAGE // Barcode Scanner
+ // What else supports this intent?
+ );
+
+ private final Activity activity;
+ private String title;
+ private String message;
+ private String buttonYes;
+ private String buttonNo;
+ private List<String> targetApplications;
+ private final Map<String,Object> moreExtras;
+
+ public IntentIntegrator(Activity activity) {
+ this.activity = activity;
+ title = DEFAULT_TITLE;
+ message = DEFAULT_MESSAGE;
+ buttonYes = DEFAULT_YES;
+ buttonNo = DEFAULT_NO;
+ targetApplications = TARGET_ALL_KNOWN;
+ moreExtras = new HashMap<String,Object>(3);
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setTitleByID(int titleID) {
+ title = activity.getString(titleID);
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public void setMessageByID(int messageID) {
+ message = activity.getString(messageID);
+ }
+
+ public String getButtonYes() {
+ return buttonYes;
+ }
+
+ public void setButtonYes(String buttonYes) {
+ this.buttonYes = buttonYes;
+ }
+
+ public void setButtonYesByID(int buttonYesID) {
+ buttonYes = activity.getString(buttonYesID);
+ }
+
+ public String getButtonNo() {
+ return buttonNo;
+ }
+
+ public void setButtonNo(String buttonNo) {
+ this.buttonNo = buttonNo;
+ }
+
+ public void setButtonNoByID(int buttonNoID) {
+ buttonNo = activity.getString(buttonNoID);
+ }
+
+ public Collection<String> getTargetApplications() {
+ return targetApplications;
+ }
+
+ public final void setTargetApplications(List<String> targetApplications) {
+ if (targetApplications.isEmpty()) {
+ throw new IllegalArgumentException("No target applications");
+ }
+ this.targetApplications = targetApplications;
+ }
+
+ public void setSingleTargetApplication(String targetApplication) {
+ this.targetApplications = Collections.singletonList(targetApplication);
+ }
+
+ public Map<String,?> getMoreExtras() {
+ return moreExtras;
+ }
+
+ public final void addExtra(String key, Object value) {
+ moreExtras.put(key, value);
+ }
+
+ /**
+ * Initiates a scan for all known barcode types.
+ */
+ public final AlertDialog initiateScan() {
+ return initiateScan(ALL_CODE_TYPES);
+ }
+
+ /**
+ * Initiates a scan only for a certain set of barcode types, given as strings corresponding
+ * to their names in ZXing's {@code BarcodeFormat} class like "UPC_A". You can supply constants
+ * like {@link #PRODUCT_CODE_TYPES} for example.
+ *
+ * @return the {@link AlertDialog} that was shown to the user prompting them to download the app
+ * if a prompt was needed, or null otherwise
+ */
+ public final AlertDialog initiateScan(Collection<String> desiredBarcodeFormats) {
+ Intent intentScan = new Intent(BS_PACKAGE + ".SCAN");
+ intentScan.addCategory(Intent.CATEGORY_DEFAULT);
+
+ // check which types of codes to scan for
+ if (desiredBarcodeFormats != null) {
+ // set the desired barcode types
+ StringBuilder joinedByComma = new StringBuilder();
+ for (String format : desiredBarcodeFormats) {
+ if (joinedByComma.length() > 0) {
+ joinedByComma.append(',');
+ }
+ joinedByComma.append(format);
+ }
+ intentScan.putExtra("SCAN_FORMATS", joinedByComma.toString());
+ }
+
+ String targetAppPackage = findTargetAppPackage(intentScan);
+ if (targetAppPackage == null) {
+ return showDownloadDialog();
+ }
+ intentScan.setPackage(targetAppPackage);
+ intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ attachMoreExtras(intentScan);
+ startActivityForResult(intentScan, REQUEST_CODE);
+ return null;
+ }
+
+ /**
+ * Start an activity. This method is defined to allow different methods of activity starting for
+ * newer versions of Android and for compatibility library.
+ *
+ * @param intent Intent to start.
+ * @param code Request code for the activity
+ * @see android.app.Activity#startActivityForResult(Intent, int)
+ * @see android.app.Fragment#startActivityForResult(Intent, int)
+ */
+ protected void startActivityForResult(Intent intent, int code) {
+ activity.startActivityForResult(intent, code);
+ }
+
+ private String findTargetAppPackage(Intent intent) {
+ PackageManager pm = activity.getPackageManager();
+ List<ResolveInfo> availableApps = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (availableApps != null) {
+ for (String targetApp : targetApplications) {
+ if (contains(availableApps, targetApp)) {
+ return targetApp;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean contains(Iterable<ResolveInfo> availableApps, String targetApp) {
+ for (ResolveInfo availableApp : availableApps) {
+ String packageName = availableApp.activityInfo.packageName;
+ if (targetApp.equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private AlertDialog showDownloadDialog() {
+ AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
+ downloadDialog.setTitle(title);
+ downloadDialog.setMessage(message);
+ downloadDialog.setPositiveButton(buttonYes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ String packageName;
+ if (targetApplications.contains(BS_PACKAGE)) {
+ // Prefer to suggest download of BS if it's anywhere in the list
+ packageName = BS_PACKAGE;
+ } else {
+ // Otherwise, first option:
+ packageName = targetApplications.get(0);
+ }
+ Uri uri = Uri.parse("market://details?id=" + packageName);
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ try {
+ activity.startActivity(intent);
+ } catch (ActivityNotFoundException anfe) {
+ // Hmm, market is not installed
+ Log.w(TAG, "Google Play is not installed; cannot install " + packageName);
+ }
+ }
+ });
+ downloadDialog.setNegativeButton(buttonNo, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {}
+ });
+ return downloadDialog.show();
+ }
+
+
+ /**
+ * <p>Call this from your {@link Activity}'s
+ * {@link Activity#onActivityResult(int, int, Intent)} method.</p>
+ *
+ * @return null if the event handled here was not related to this class, or
+ * else an {@link IntentResult} containing the result of the scan. If the user cancelled scanning,
+ * the fields will be null.
+ */
+ public static IntentResult parseActivityResult(int requestCode, int resultCode, Intent intent) {
+ if (requestCode == REQUEST_CODE) {
+ if (resultCode == Activity.RESULT_OK) {
+ String contents = intent.getStringExtra("SCAN_RESULT");
+ String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT");
+ byte[] rawBytes = intent.getByteArrayExtra("SCAN_RESULT_BYTES");
+ int intentOrientation = intent.getIntExtra("SCAN_RESULT_ORIENTATION", Integer.MIN_VALUE);
+ Integer orientation = intentOrientation == Integer.MIN_VALUE ? null : intentOrientation;
+ String errorCorrectionLevel = intent.getStringExtra("SCAN_RESULT_ERROR_CORRECTION_LEVEL");
+ return new IntentResult(contents,
+ formatName,
+ rawBytes,
+ orientation,
+ errorCorrectionLevel);
+ }
+ return new IntentResult();
+ }
+ return null;
+ }
+
+
+ /**
+ * Defaults to type "TEXT_TYPE".
+ * @see #shareText(CharSequence, CharSequence)
+ */
+ public final AlertDialog shareText(CharSequence text) {
+ return shareText(text, "TEXT_TYPE");
+ }
+
+ /**
+ * Shares the given text by encoding it as a barcode, such that another user can
+ * scan the text off the screen of the device.
+ *
+ * @param text the text string to encode as a barcode
+ * @param type type of data to encode. See {@code com.google.zxing.client.android.Contents.Type} constants.
+ * @return the {@link AlertDialog} that was shown to the user prompting them to download the app
+ * if a prompt was needed, or null otherwise
+ */
+ public final AlertDialog shareText(CharSequence text, CharSequence type) {
+ Intent intent = new Intent();
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setAction(BS_PACKAGE + ".ENCODE");
+ intent.putExtra("ENCODE_TYPE", type);
+ intent.putExtra("ENCODE_DATA", text);
+ String targetAppPackage = findTargetAppPackage(intent);
+ if (targetAppPackage == null) {
+ return showDownloadDialog();
+ }
+ intent.setPackage(targetAppPackage);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ attachMoreExtras(intent);
+ activity.startActivity(intent);
+ return null;
+ }
+
+ private static List<String> list(String... values) {
+ return Collections.unmodifiableList(Arrays.asList(values));
+ }
+
+ private void attachMoreExtras(Intent intent) {
+ for (Map.Entry<String,Object> entry : moreExtras.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ // Kind of hacky
+ if (value instanceof Integer) {
+ intent.putExtra(key, (Integer) value);
+ } else if (value instanceof Long) {
+ intent.putExtra(key, (Long) value);
+ } else if (value instanceof Boolean) {
+ intent.putExtra(key, (Boolean) value);
+ } else if (value instanceof Double) {
+ intent.putExtra(key, (Double) value);
+ } else if (value instanceof Float) {
+ intent.putExtra(key, (Float) value);
+ } else if (value instanceof Bundle) {
+ intent.putExtra(key, (Bundle) value);
+ } else {
+ intent.putExtra(key, value.toString());
+ }
+ }
+ }
+
+}
diff --git a/libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentResult.java b/libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentResult.java
new file mode 100644
index 000000000..2469af92c
--- /dev/null
+++ b/libraries/zxing-android-integration/src/com/google/zxing/integration/android/IntentResult.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2009 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing.integration.android;
+
+/**
+ * <p>Encapsulates the result of a barcode scan invoked through {@link IntentIntegrator}.</p>
+ *
+ * @author Sean Owen
+ */
+public final class IntentResult {
+
+ private final String contents;
+ private final String formatName;
+ private final byte[] rawBytes;
+ private final Integer orientation;
+ private final String errorCorrectionLevel;
+
+ IntentResult() {
+ this(null, null, null, null, null);
+ }
+
+ IntentResult(String contents,
+ String formatName,
+ byte[] rawBytes,
+ Integer orientation,
+ String errorCorrectionLevel) {
+ this.contents = contents;
+ this.formatName = formatName;
+ this.rawBytes = rawBytes;
+ this.orientation = orientation;
+ this.errorCorrectionLevel = errorCorrectionLevel;
+ }
+
+ /**
+ * @return raw content of barcode
+ */
+ public String getContents() {
+ return contents;
+ }
+
+ /**
+ * @return name of format, like "QR_CODE", "UPC_A". See {@code BarcodeFormat} for more format names.
+ */
+ public String getFormatName() {
+ return formatName;
+ }
+
+ /**
+ * @return raw bytes of the barcode content, if applicable, or null otherwise
+ */
+ public byte[] getRawBytes() {
+ return rawBytes;
+ }
+
+ /**
+ * @return rotation of the image, in degrees, which resulted in a successful scan. May be null.
+ */
+ public Integer getOrientation() {
+ return orientation;
+ }
+
+ /**
+ * @return name of the error correction level used in the barcode, if applicable
+ */
+ public String getErrorCorrectionLevel() {
+ return errorCorrectionLevel;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder dialogText = new StringBuilder(100);
+ dialogText.append("Format: ").append(formatName).append('\n');
+ dialogText.append("Contents: ").append(contents).append('\n');
+ int rawBytesLength = rawBytes == null ? 0 : rawBytes.length;
+ dialogText.append("Raw bytes: (").append(rawBytesLength).append(" bytes)\n");
+ dialogText.append("Orientation: ").append(orientation).append('\n');
+ dialogText.append("EC level: ").append(errorCorrectionLevel).append('\n');
+ return dialogText.toString();
+ }
+
+}
diff --git a/libraries/zxing/.gitignore b/libraries/zxing/.gitignore
new file mode 100644
index 000000000..71c11b159
--- /dev/null
+++ b/libraries/zxing/.gitignore
@@ -0,0 +1,30 @@
+#Android specific
+bin
+gen
+obj
+libs/armeabi
+lint.xml
+local.properties
+release.properties
+ant.properties
+*.class
+*.apk
+
+#Gradle
+.gradle
+build
+gradle.properties
+
+#Maven
+target
+pom.xml.*
+
+#Eclipse
+.project
+.classpath
+.settings
+.metadata
+
+#IntelliJ IDEA
+.idea
+*.iml
diff --git a/settings.gradle b/settings.gradle
index 5602503ee..021c54832 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,5 +2,6 @@ include ':OpenPGP-Keychain'
include ':libraries:ActionBarSherlock'
include ':libraries:HtmlTextView'
include ':libraries:StickyListHeaders:library'
-include ':libraries:zxing'
include ':libraries:AndroidBootstrap'
+include ':libraries:zxing'
+include ':libraries:zxing-android-integration'