diff options
37 files changed, 220 insertions, 138 deletions
diff --git a/.travis.yml b/.travis.yml index 946125fe0..54db1a965 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools # Install required Android components. - - echo "y" | android update sdk -a --filter build-tools-19.0.3,android-19,platform-tools,extra-android-support,extra-android-m2repository,android-17 --no-ui --force + - echo "y" | android update sdk -a --filter build-tools-19.0.3,android-19,platform-tools,extra-android-support,extra-android-m2repository --no-ui --force install: echo "Installation done" script: gradle assemble -S -q diff --git a/OpenPGP-Keychain-API/build.gradle b/OpenPGP-Keychain-API/build.gradle index 2e41492a3..47a0f376a 100644 --- a/OpenPGP-Keychain-API/build.gradle +++ b/OpenPGP-Keychain-API/build.gradle @@ -1,3 +1,3 @@ task wrapper(type: Wrapper) { - gradleVersion = '1.10' -}
\ No newline at end of file + gradleVersion = '1.11' +} diff --git a/OpenPGP-Keychain-API/example-app/build.gradle b/OpenPGP-Keychain-API/example-app/build.gradle index 975666b19..5147dc7bc 100644 --- a/OpenPGP-Keychain-API/example-app/build.gradle +++ b/OpenPGP-Keychain-API/example-app/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.8.3' + classpath 'com.android.tools.build:gradle:0.9.0' } } diff --git a/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java b/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java index 4d143ade6..a660b1c9a 100644 --- a/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java +++ b/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java @@ -202,7 +202,7 @@ public class OpenPgpProviderActivity extends Activity { break; } case OpenPgpApi.RESULT_CODE_ERROR: { - OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERRORS); + OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); handleError(error); break; } @@ -234,7 +234,7 @@ public class OpenPgpProviderActivity extends Activity { } public void signAndEncrypt(Intent data) { - data.setAction(OpenPgpApi.ACTION_SIGN_AND_ENCTYPT); + data.setAction(OpenPgpApi.ACTION_SIGN_AND_ENCRYPT); data.putExtra(OpenPgpApi.EXTRA_USER_IDS, mEncryptUserIds.getText().toString().split(",")); data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); diff --git a/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.jar b/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.jar Binary files differindex 583859812..3c7abdf12 100644 --- a/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.jar +++ b/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.jar diff --git a/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties b/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties index 932184188..8c3a98441 100644 --- a/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties +++ b/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Feb 14 01:26:40 CET 2014 +#Thu Mar 06 18:21:41 CET 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle b/OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle index 7c923e7f6..98c9a3bd6 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.8.3' + classpath 'com.android.tools.build:gradle:0.9.0' } } diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java index ed1a7540a..f0eae4a47 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java @@ -16,101 +16,110 @@ package org.openintents.openpgp.util; +import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Build; import android.os.ParcelFileDescriptor; import android.util.Log; - import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.OpenPgpError; - import java.io.InputStream; import java.io.OutputStream; public class OpenPgpApi { - //TODO: fix this documentation + public static final String TAG = "OpenPgp API"; + + public static final int API_VERSION = 2; + public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; + /** - * General extras - * -------------- - * - * Intent extras: - * int api_version (required) - * boolean ascii_armor (request ascii armor for ouput) + * Sign only * - * returned Bundle: - * int result_code (0, 1, or 2 (see OpenPgpApi)) - * OpenPgpError error (if result_code == 0) - * Intent intent (if result_code == 2) + * optional params: + * String EXTRA_PASSPHRASE (for key passphrase) */ + public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN"; /** - * Sign only + * General extras + * -------------- * - * optional params: - * String passphrase (for key passphrase) + * Intent extras: + * int EXTRA_API_VERSION (required) + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * + * returned extras: + * int RESULT_CODE (0, 1, or 2 (see OpenPgpApi)) + * OpenPgpError RESULT_ERROR (if result_code == 0) + * Intent RESULT_INTENT (if result_code == 2) */ /** * Encrypt * - * Intent extras: - * long[] key_ids + * extras: + * long[] EXTRA_KEY_IDS * or - * String[] user_ids (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned) + * String[] EXTRA_USER_IDS (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned) * * optional extras: - * String passphrase (for key passphrase) + * String EXTRA_PASSPHRASE (for key passphrase) */ + public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT"; /** * Sign and encrypt * - * Intent extras: - * same as in encrypt() + * extras: + * long[] EXTRA_KEY_IDS + * or + * String[] EXTRA_USER_IDS (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned) + * + * optional extras: + * String EXTRA_PASSPHRASE (for key passphrase) */ + public static final String ACTION_SIGN_AND_ENCRYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT"; /** * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, * and also signed-only input. * - * returned Bundle: - * OpenPgpSignatureResult signature_result + * returned extras: + * OpenPgpSignatureResult RESULT_SIGNATURE */ + public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY"; /** - * Retrieves key ids based on given user ids (=emails) + * Get key ids based on given user ids (=emails) * * Intent extras: - * String[] user_ids + * String[] EXTRA_KEY_IDS * - * returned Bundle: - * long[] key_ids + * returned extras: + * long[] EXTRA_USER_IDS */ + public static final String ACTION_GET_KEY_IDS = "org.openintents.openpgp.action.GET_KEY_IDS"; - public static final String TAG = "OpenPgp API"; - - public static final int API_VERSION = 2; - public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; - - public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN"; - public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT"; - public static final String ACTION_SIGN_AND_ENCTYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT"; - public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY"; + /** + * Download keys from keyserver + * + * Intent extras: + * String[] EXTRA_KEY_IDS + */ public static final String ACTION_DOWNLOAD_KEYS = "org.openintents.openpgp.action.DOWNLOAD_KEYS"; - public static final String ACTION_GET_KEY_IDS = "org.openintents.openpgp.action.GET_KEY_IDS"; /* Bundle params */ public static final String EXTRA_API_VERSION = "api_version"; - // SIGN, ENCRYPT, SIGN_ENCRYPT, DECRYPT_VERIFY + // SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY // request ASCII Armor for output // OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) public static final String EXTRA_REQUEST_ASCII_ARMOR = "ascii_armor"; - // ENCRYPT, SIGN_ENCRYPT + // ENCRYPT, SIGN_AND_ENCRYPT public static final String EXTRA_USER_IDS = "user_ids"; public static final String EXTRA_KEY_IDS = "key_ids"; // optional parameter: @@ -118,17 +127,19 @@ public class OpenPgpApi { /* Service Bundle returns */ public static final String RESULT_CODE = "result_code"; - public static final String RESULT_SIGNATURE = "signature"; - public static final String RESULT_ERRORS = "error"; - public static final String RESULT_INTENT = "intent"; - // get actual error object from RESULT_ERRORS + // get actual error object from RESULT_ERROR public static final int RESULT_CODE_ERROR = 0; // success! public static final int RESULT_CODE_SUCCESS = 1; // executeServiceMethod intent and do it again with intent public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2; + public static final String RESULT_ERROR = "error"; + public static final String RESULT_INTENT = "intent"; + + // DECRYPT_VERIFY + public static final String RESULT_SIGNATURE = "signature"; IOpenPgpService mService; Context mContext; @@ -166,6 +177,7 @@ public class OpenPgpApi { } + @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void executeApiAsync(Intent data, InputStream is, OutputStream os, IOpenPgpCallback callback) { OpenPgpAsyncTask task = new OpenPgpAsyncTask(data, is, os, callback); @@ -188,13 +200,13 @@ public class OpenPgpApi { result = mService.execute(data, null, null); return result; } else { - // send the input and output pfds + // pipe the input and output ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is, new ParcelFileDescriptorUtil.IThreadListener() { @Override public void onThreadFinished(Thread thread) { - Log.d(OpenPgpApi.TAG, "Copy to service finished"); + //Log.d(OpenPgpApi.TAG, "Copy to service finished"); } }); ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os, @@ -202,7 +214,7 @@ public class OpenPgpApi { @Override public void onThreadFinished(Thread thread) { - Log.d(OpenPgpApi.TAG, "Service finished writing!"); + //Log.d(OpenPgpApi.TAG, "Service finished writing!"); } }); @@ -222,7 +234,7 @@ public class OpenPgpApi { Log.e(OpenPgpApi.TAG, "Exception", e); Intent result = new Intent(); result.putExtra(RESULT_CODE, RESULT_CODE_ERROR); - result.putExtra(RESULT_ERRORS, + result.putExtra(RESULT_ERROR, new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage())); return result; } diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml index 10a307bfb..8aa37393f 100644 --- a/OpenPGP-Keychain/src/main/AndroidManifest.xml +++ b/OpenPGP-Keychain/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.sufficientlysecure.keychain" android:installLocation="auto" - android:versionCode="23102" - android:versionName="2.3.1 beta2"> + android:versionCode="23103" + android:versionName="2.3.1 beta3"> <!-- General remarks @@ -69,30 +69,12 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> - - <!-- <intent-filter> --> - <!-- <action android:name="android.intent.action.SEARCH" /> --> - <!-- </intent-filter> --> - - - <!-- <meta-data --> - <!-- android:name="android.app.searchable" --> - <!-- android:resource="@xml/searchable_public_keys" /> --> </activity> <activity android:name=".ui.KeyListSecretActivity" android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:label="@string/title_manage_secret_keys" android:launchMode="singleTop"> - - <!-- <intent-filter> --> - <!-- <action android:name="android.intent.action.SEARCH" /> --> - <!-- </intent-filter> --> - - - <!-- <meta-data --> - <!-- android:name="android.app.searchable" --> - <!-- android:resource="@xml/searchable_secret_keys" /> --> </activity> <activity android:name=".ui.EditKeyActivity" @@ -122,30 +104,12 @@ android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:label="@string/title_select_recipients" android:launchMode="singleTop"> - - <!-- <intent-filter> --> - <!-- <action android:name="android.intent.action.SEARCH" /> --> - <!-- </intent-filter> --> - - - <!-- <meta-data --> - <!-- android:name="android.app.searchable" --> - <!-- android:resource="@xml/searchable_public_keys" /> --> </activity> <activity android:name=".ui.SelectSecretKeyActivity" android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:label="@string/title_select_secret_key" android:launchMode="singleTop"> - - <!-- <intent-filter> --> - <!-- <action android:name="android.intent.action.SEARCH" /> --> - <!-- </intent-filter> --> - - - <!-- <meta-data --> - <!-- android:name="android.app.searchable" --> - <!-- android:resource="@xml/searchable_secret_keys" /> --> </activity> <activity android:name=".ui.EncryptActivity" @@ -464,10 +428,6 @@ <!--<intent-filter>--> <!--<action android:name="org.sufficientlysecure.keychain.service.remote.IExtendedApiService" />--> <!--</intent-filter>--> - - <!--<meta-data--> - <!--android:name="api_version"--> - <!--android:value="1" />--> <!--</service>--> <!-- TODO: authority! Make this API with content provider uris --> diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index c568f462a..ccd6ff8df 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -335,7 +335,7 @@ public class PgpDecryptVerify { currentProgress += 5; updateProgress(R.string.progress_extracting_key, currentProgress, 100); - PGPPrivateKey privateKey = null; + PGPPrivateKey privateKey; try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( @@ -593,6 +593,8 @@ public class PgpDecryptVerify { if (signature == null) { signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); + returnData.setSignatureResult(signatureResult); + updateProgress(R.string.progress_done, 100, 100); return returnData; } @@ -630,9 +632,9 @@ public class PgpDecryptVerify { // TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR???? - updateProgress(R.string.progress_done, 100, 100); - returnData.setSignatureResult(signatureResult); + + updateProgress(R.string.progress_done, 100, 100); return returnData; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java index 8b34c4421..e1801d9e7 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java @@ -180,7 +180,7 @@ public class OpenPgpService extends RemoteService { } catch (Exception e) { Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); return result; } @@ -209,7 +209,7 @@ public class OpenPgpService extends RemoteService { } else { Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!")); return result; } @@ -268,7 +268,7 @@ public class OpenPgpService extends RemoteService { } catch (Exception e) { Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); return result; } @@ -334,7 +334,7 @@ public class OpenPgpService extends RemoteService { } catch (Exception e) { Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); return result; } @@ -361,7 +361,7 @@ public class OpenPgpService extends RemoteService { if (data == null) { Intent result = new Intent(); OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); - result.putExtra(OpenPgpApi.RESULT_ERRORS, error); + result.putExtra(OpenPgpApi.RESULT_ERROR, error); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } @@ -370,7 +370,7 @@ public class OpenPgpService extends RemoteService { if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) { Intent result = new Intent(); OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); - result.putExtra(OpenPgpApi.RESULT_ERRORS, error); + result.putExtra(OpenPgpApi.RESULT_ERROR, error); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } @@ -401,7 +401,7 @@ public class OpenPgpService extends RemoteService { return signImpl(data, input, output, appSettings); } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { return encryptAndSignImpl(data, input, output, appSettings, false); - } else if (OpenPgpApi.ACTION_SIGN_AND_ENCTYPT.equals(action)) { + } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { return encryptAndSignImpl(data, input, output, appSettings, true); } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { return decryptAndVerifyImpl(data, input, output, appSettings); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java index e7b3b2945..cb556be39 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java @@ -72,7 +72,7 @@ public abstract class RemoteService extends Service { // return error Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); return result; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index 0afa556cb..f2cb8a265 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -46,9 +46,13 @@ import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.widget.SearchView; +import android.text.TextUtils; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; @@ -64,23 +68,25 @@ import com.beardedhen.androidbootstrap.BootstrapButton; * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses * StickyListHeaders library which does not extend upon ListView. */ -public class KeyListPublicFragment extends Fragment implements AdapterView.OnItemClickListener, +public class KeyListPublicFragment extends Fragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor> { private KeyListPublicAdapter mAdapter; private StickyListHeadersListView mStickyList; - + private String mCurQuery; + private SearchView mSearchView; // empty list layout private BootstrapButton mButtonEmptyCreate; private BootstrapButton mButtonEmptyImport; + /** * Load custom layout with StickyListView from library */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.key_list_public_fragment, container, false); - + setHasOptionsMenu(true); mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create); mButtonEmptyCreate.setOnClickListener(new OnClickListener() { @@ -138,8 +144,6 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { - private int count = 0; - @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { android.view.MenuInflater inflater = getActivity().getMenuInflater(); @@ -173,13 +177,20 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte showDeleteKeyDialog(mode, ids); break; } + case R.id.menu_key_list_public_multi_select_all: { + //Select all + int localCount = mStickyList.getCount(); + for(int k = 0; k < localCount; k++) { + mStickyList.setItemChecked(k, true); + } + break; + } } return true; } @Override public void onDestroyActionMode(ActionMode mode) { - count = 0; mAdapter.clearSelection(); } @@ -187,13 +198,11 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { - count++; mAdapter.setNewSelection(position, checked); } else { - count--; mAdapter.removeSelection(position); } - + int count = mAdapter.getCurrentCheckedPosition().size(); String keysSelected = getResources().getQuantityString( R.plurals.key_list_selected_keys, count, count); mode.setTitle(keysSelected); @@ -232,10 +241,15 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. Uri baseUri = KeyRings.buildPublicKeyRingsUri(); - + String where = null; + String whereArgs[] = null; + if(mCurQuery != null){ + where = KeychainContract.UserIds.USER_ID + " LIKE ?"; + whereArgs = new String[]{mCurQuery+"%"}; + } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, SORT_ORDER); + return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, SORT_ORDER); } @Override @@ -335,4 +349,34 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); } + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + + // Get the searchview + MenuItem searchItem = menu.findItem(R.id.menu_key_list_public_search); + mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem); + + // Execute this when searching + mSearchView.setOnQueryTextListener(this); + + super.onCreateOptionsMenu(menu, inflater); + + } + + @Override + public boolean onQueryTextSubmit(String s) { + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + String newQuery = !TextUtils.isEmpty(s) ? s : null; + mCurQuery = newQuery; + getLoaderManager().restartLoader(0, null, this); + return true; + } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index 7bb77b60f..eaac6d8b1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -82,8 +82,6 @@ public class KeyListSecretFragment extends ListFragment implements getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() { - private int count = 0; - @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { android.view.MenuInflater inflater = getActivity().getMenuInflater(); @@ -113,13 +111,20 @@ public class KeyListSecretFragment extends ListFragment implements showDeleteKeyDialog(mode, ids); break; } + case R.id.menu_key_list_public_multi_select_all: { + //Select all + int localCount = getListView().getCount(); + for(int k = 0; k < localCount; k++) { + getListView().setItemChecked(k, true); + } + break; + } } return true; } @Override public void onDestroyActionMode(ActionMode mode) { - count = 0; mAdapter.clearSelection(); } @@ -127,13 +132,12 @@ public class KeyListSecretFragment extends ListFragment implements public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { - count++; mAdapter.setNewSelection(position, checked); } else { - count--; mAdapter.removeSelection(position); } + int count = getListView().getCheckedItemCount(); String keysSelected = getResources().getQuantityString( R.plurals.key_list_selected_keys, count, count); mode.setTitle(keysSelected); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java index 59b46dd00..a43c84cf4 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java @@ -38,17 +38,22 @@ import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.widget.EditText; import android.widget.ListView; -public class SelectPublicKeyFragment extends ListFragmentWorkaround implements +public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher, LoaderManager.LoaderCallbacks<Cursor> { public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids"; private Activity mActivity; private SelectKeyCursorAdapter mAdapter; private ListView mListView; - + private EditText mSearchView; private long mSelectedMasterKeyIds[]; + private String mCurQuery; /** * Creates new instance of this fragment @@ -67,7 +72,8 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + mSearchView = (EditText)getActivity().findViewById(R.id.select_public_key_search); + mSearchView.addTextChangedListener(this); mSelectedMasterKeyIds = getArguments().getLongArray(ARG_PRESELECTED_KEY_IDS); } @@ -82,7 +88,6 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements mListView = getListView(); mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - // Give some text to display if there is no data. In a real // application this would come from a resource. setEmptyText(getString(R.string.list_empty)); @@ -220,10 +225,16 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements // sort by selected master keys orderBy = inMasterKeyList + " DESC, " + orderBy; } + String where = null; + String whereArgs[] = null; + if(mCurQuery != null){ + where = UserIds.USER_ID + " LIKE ?"; + whereArgs = new String[]{mCurQuery+"%"}; + } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, projection, null, null, orderBy); + return new CursorLoader(getActivity(), baseUri, projection, where, whereArgs, orderBy); } @Override @@ -250,4 +261,21 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements // longer using it. mAdapter.swapCursor(null); } + + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void afterTextChanged(Editable editable) { + String newQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null; + mCurQuery = newQuery; + getLoaderManager().restartLoader(0, null, this); + } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java index 257136cbd..ac505adfb 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -223,7 +223,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea */ // default color v.setBackgroundColor(Color.TRANSPARENT); - if (mSelection.get(position) != null) { + if (mSelection.get(position) != null && mSelection.get(position).booleanValue()) { // this is a selected position, change color! v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); } diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_search.png Binary files differnew file mode 100644 index 000000000..f594b4e48 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_search.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_secure.png Binary files differnew file mode 100644 index 000000000..287ae2fb0 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_secure.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_select_all.png Binary files differnew file mode 100644 index 000000000..fc0dd57b6 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_select_all.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_search.png Binary files differnew file mode 100644 index 000000000..f6719d228 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_search.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_secure.png Binary files differnew file mode 100644 index 000000000..d49217234 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_secure.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_select_all.png Binary files differnew file mode 100644 index 000000000..da37d7a6e --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_select_all.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_search.png Binary files differnew file mode 100644 index 000000000..aad535e97 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_search.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_secure.png Binary files differnew file mode 100644 index 000000000..2a0898381 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_secure.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_select_all.png Binary files differnew file mode 100644 index 000000000..af37a3680 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_select_all.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_search.png Binary files differnew file mode 100644 index 000000000..9c0ea3ca0 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_search.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_secure.png Binary files differnew file mode 100644 index 000000000..d8c094ed8 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_secure.png diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_select_all.png Binary files differnew file mode 100644 index 000000000..aa5937eab --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_select_all.png diff --git a/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml b/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml index a18ce46fc..5337433c6 100644 --- a/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml @@ -4,8 +4,16 @@ android:layout_height="match_parent" android:layout_centerHorizontal="true" > + <EditText + android:id="@+id/select_public_key_search" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/menu_search" + android:drawableLeft="@drawable/ic_action_search"/> + <FrameLayout android:id="@+id/select_public_key_fragment_container" + android:layout_below="@id/select_public_key_search" android:layout_width="match_parent" android:layout_height="match_parent" /> diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml index cdd755dc3..35a8f3926 100644 --- a/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml +++ b/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml @@ -11,5 +11,10 @@ android:id="@+id/menu_key_list_public_export" app:showAsAction="never" android:title="@string/menu_export_keys" /> - + <item + android:id="@+id/menu_key_list_public_search" + android:title="@string/menu_search" + android:icon="@drawable/ic_action_search" + app:actionViewClass="android.support.v7.widget.SearchView" + app:showAsAction="ifRoom" /> </menu>
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_public_multi.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_public_multi.xml index f7b415441..d30ee5e8f 100644 --- a/OpenPGP-Keychain/src/main/res/menu/key_list_public_multi.xml +++ b/OpenPGP-Keychain/src/main/res/menu/key_list_public_multi.xml @@ -2,7 +2,12 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item + android:id="@+id/menu_key_list_public_multi_select_all" + android:icon="@drawable/ic_action_select_all" + android:title="@string/menu_select_all" /> + <item android:id="@+id/menu_key_list_public_multi_encrypt" + android:icon="@drawable/ic_action_secure" android:title="@string/menu_encrypt_to" /> <item android:id="@+id/menu_key_list_public_multi_delete" diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml index 9cfab9fd3..a3375c7e8 100644 --- a/OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml +++ b/OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml @@ -2,6 +2,10 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item + android:id="@+id/menu_key_list_public_multi_select_all" + android:icon="@drawable/ic_action_select_all" + android:title="@string/menu_select_all" /> + <item android:id="@+id/menu_key_list_public_multi_delete" android:icon="@drawable/ic_action_discard" android:title="@string/menu_delete_key" /> diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml index 34dc26571..fef83c936 100644 --- a/OpenPGP-Keychain/src/main/res/values/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values/strings.xml @@ -96,6 +96,7 @@ <string name="menu_beam_preferences">Beam settings</string> <string name="menu_key_edit_cancel">Cancel</string> <string name="menu_encrypt_to">Encrypt to…</string> + <string name="menu_select_all">Select all</string> <!-- label --> <string name="label_sign">Sign</string> @@ -116,6 +116,15 @@ When changing build files or dependencies, respect the following requirements: * No dependencies from Maven (also a soft requirement for inclusion in [F-Droid](https://f-droid.org)) * Always use a fixed Android Gradle plugin version not a dynamic one, e.g. ``0.7.3`` instead of ``0.7.+`` (allows offline builds without lookups for new versions, also some minor Android plugin versions had serious issues, i.e. [0.7.2 and 0.8.1](http://tools.android.com/tech-docs/new-build-system)) * Commit the corresponding [Gradle wrapper](http://www.gradle.org/docs/current/userguide/gradle_wrapper.html) to the repository (allows easy building for new contributors without the need to install the required Gradle version using a package manager) +* In order to update the build system to a newer gradle version you need to: + * Update every build.gradle file with the new gradle version and/or gradle plugin version + * build.gradle + * OpenPGP-Keychain/build.gradle + * OpenPGP-Keychain-API/build.gradle + * OpenPGP-Keychain-API/example-app/build.gradle + * OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle + * run ./gradlew wrapper twice to update gradle and download the new jar file + * commit the new jar and property files ### Translations diff --git a/build.gradle b/build.gradle index 86c40fa3a..305e8d1b9 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.8.3' + classpath 'com.android.tools.build:gradle:0.9.0' } } @@ -15,5 +15,5 @@ allprojects { } task wrapper(type: Wrapper) { - gradleVersion = '1.10' -}
\ No newline at end of file + gradleVersion = '1.11' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar Binary files differindex 583859812..3c7abdf12 100644 --- a/gradle/wrapper/gradle-wrapper.jar +++ b/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9559bfd8b..9c0d6700a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Feb 09 18:34:27 CET 2014 +#Thu Mar 06 18:21:40 CET 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip |