diff options
Diffstat (limited to 'OpenPGP-Keychain/src')
27 files changed, 420 insertions, 215 deletions
diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml index 8aa37393f..10f112f23 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="23103" - android:versionName="2.3.1 beta3"> + android:versionCode="23104" + android:versionName="2.3.1 beta4"> <!-- General remarks diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index 9d9cd4d11..7c635a00b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -228,7 +228,7 @@ public class PgpImportExport { for (PGPSecretKey testSecretKey : new IterableIterator<PGPSecretKey>( secretKeyRing.getSecretKeys())) { if (!testSecretKey.isMasterKey()) { - if (PgpKeyHelper.isSecretKeyPrivateEmpty(testSecretKey)) { + if (testSecretKey.isPrivateKeyEmpty()) { // this is bad, something is very wrong... save = false; status = Id.return_value.bad; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index b3e21685e..71c921c33 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -32,6 +32,7 @@ import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -415,55 +416,30 @@ public class PgpKeyHelper { String algorithmStr = null; switch (algorithm) { - case PGPPublicKey.RSA_ENCRYPT: - case PGPPublicKey.RSA_GENERAL: - case PGPPublicKey.RSA_SIGN: { - algorithmStr = "RSA"; - break; - } - - case PGPPublicKey.DSA: { - algorithmStr = "DSA"; - break; - } - - case PGPPublicKey.ELGAMAL_ENCRYPT: - case PGPPublicKey.ELGAMAL_GENERAL: { - algorithmStr = "ElGamal"; - break; - } + case PGPPublicKey.RSA_ENCRYPT: + case PGPPublicKey.RSA_GENERAL: + case PGPPublicKey.RSA_SIGN: { + algorithmStr = "RSA"; + break; + } - default: { - algorithmStr = "Unknown"; - break; - } - } - return algorithmStr + ", " + keySize + " bit"; - } + case PGPPublicKey.DSA: { + algorithmStr = "DSA"; + break; + } - /** - * Converts fingerprint to hex with whitespaces after 4 characters - * - * @param fp - * @return - */ - public static String convertFingerprintToHex(byte[] fp, boolean chunked) { - String fingerPrint = ""; - for (int i = 0; i < fp.length; ++i) { - if (chunked && i != 0 && i % 10 == 0) { - fingerPrint += " "; - } else if (chunked && i != 0 && i % 2 == 0) { - fingerPrint += " "; + case PGPPublicKey.ELGAMAL_ENCRYPT: + case PGPPublicKey.ELGAMAL_GENERAL: { + algorithmStr = "ElGamal"; + break; } - String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase(Locale.US); - while (chunk.length() < 2) { - chunk = "0" + chunk; + + default: { + algorithmStr = "Unknown"; + break; } - fingerPrint += chunk; } - - return fingerPrint; - + return algorithmStr + ", " + keySize + " bit"; } public static String getFingerPrint(Context context, long keyId) { @@ -481,52 +457,68 @@ public class PgpKeyHelper { return convertFingerprintToHex(key.getFingerprint(), true); } - public static boolean isSecretKeyPrivateEmpty(PGPSecretKey secretKey) { - return secretKey.isPrivateKeyEmpty(); - } - -// public static boolean isSecretKeyPrivateEmpty(Context context, long keyId) { -// PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId); -// if (secretKey == null) { -// Log.e(Constants.TAG, "Key could not be found!"); -// return false; // could be a public key, assume it is not empty -// } -// return isSecretKeyPrivateEmpty(secretKey); -// } - - public static String convertKeyIdToHex(long keyId) { - String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US); - while (fingerPrint.length() < 8) { - fingerPrint = "0" + fingerPrint; + /** + * Converts fingerprint to hex (optional: with whitespaces after 4 characters) + * <p/> + * Fingerprint is shown using lowercase characters. Studies have shown that humans can + * better differentiate between numbers and letters when letters are lowercase. + * + * @param fingerprint + * @param split split into 4 character chunks + * @return + */ + public static String convertFingerprintToHex(byte[] fingerprint, boolean split) { + String hexString = Hex.toHexString(fingerprint); + if (split) { + hexString = hexString.replaceAll("(.{4})(?!$)", "$1 "); } - return fingerPrint; + + return hexString; } /** - * TODO: documentation - * + * Convert key id from long to 64 bit hex string + * <p/> + * V4: "The Key ID is the low-order 64 bits of the fingerprint" + * <p/> + * see http://tools.ietf.org/html/rfc4880#section-12.2 + * * @param keyId * @return */ - public static String convertKeyToHex(long keyId) { - return convertKeyIdToHex(keyId >> 32) + convertKeyIdToHex(keyId); + public static String convertKeyIdToHex(long keyId) { + return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId); + } + + private static String convertKeyIdToHex32bit(long keyId) { + String hexString = Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.US); + while (hexString.length() < 8) { + hexString = "0" + hexString; + } + return hexString; } - public static long convertHexToKeyId(String data) { - int len = data.length(); - String s2 = data.substring(len - 8); - String s1 = data.substring(0, len - 8); + /** + * Used in HkpKeyServer to convert hex encoded key ids back to long. + * + * @param hexString + * @return + */ + public static long convertHexToKeyId(String hexString) { + int len = hexString.length(); + String s2 = hexString.substring(len - 8); + String s1 = hexString.substring(0, len - 8); return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16); } /** * Splits userId string into naming part, email part, and comment part - * + * * @param userId * @return array with naming (0), email (1), comment (2) */ public static String[] splitUserId(String userId) { - String[] result = new String[] { null, null, null }; + String[] result = new String[]{null, null, null}; if (userId == null || userId.equals("")) { return result; @@ -547,7 +539,6 @@ public class PgpKeyHelper { result[0] = matcher.group(1); result[1] = matcher.group(3); result[2] = matcher.group(2); - return result; } return result; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 68d9f801b..ac0692213 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -87,7 +87,7 @@ public class ProviderHelper { } /** - * Retrieves the actual PGPPublicKeyRing object from the database blob based on the maserKeyId + * Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId */ public static PGPPublicKeyRing getPGPPublicKeyRingByMasterKeyId(Context context, long masterKeyId) { @@ -110,11 +110,8 @@ public class ProviderHelper { */ public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) { PGPPublicKeyRing keyRing = getPGPPublicKeyRingByKeyId(context, keyId); - if (keyRing == null) { - return null; - } - return keyRing.getPublicKey(keyId); + return (keyRing == null)? null : keyRing.getPublicKey(keyId); } /** @@ -149,11 +146,8 @@ public class ProviderHelper { */ public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) { PGPSecretKeyRing keyRing = getPGPSecretKeyRingByKeyId(context, keyId); - if (keyRing == null) { - return null; - } - return keyRing.getSecretKey(keyId); + return (keyRing == null) ? null : keyRing.getSecretKey(keyId); } /** @@ -341,10 +335,10 @@ public class ProviderHelper { long keyRingRowId, PGPSecretKey key, int rank) throws IOException { ContentValues values = new ContentValues(); - boolean has_private = true; + boolean hasPrivate = true; if (key.isMasterKey()) { - if (PgpKeyHelper.isSecretKeyPrivateEmpty(key)) { - has_private = false; + if (key.isPrivateKeyEmpty()) { + hasPrivate = false; } } @@ -352,8 +346,8 @@ public class ProviderHelper { values.put(Keys.IS_MASTER_KEY, key.isMasterKey()); values.put(Keys.ALGORITHM, key.getPublicKey().getAlgorithm()); values.put(Keys.KEY_SIZE, key.getPublicKey().getBitStrength()); - values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key) && has_private)); - values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key) && has_private)); + values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key) && hasPrivate)); + values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key) && hasPrivate)); values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key)); values.put(Keys.IS_REVOKED, key.getPublicKey().isRevoked()); values.put(Keys.CREATION, PgpKeyHelper.getCreationDate(key).getTime() / 1000); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 313655766..67ce7a395 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -596,13 +596,21 @@ public class KeychainIntentService extends IntentService implements ProgressDial String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE); /* Operation */ + int keysTotal = 2; + int keysCreated =0; + setProgress(getApplicationContext().getResources().getQuantityString(R.plurals.progress_generating,keysTotal), + keysCreated, keysTotal); PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); PGPSecretKey masterKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, true); + keysCreated++; + setProgress(keysCreated, keysTotal); PGPSecretKey subKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, false); + keysCreated++; + setProgress(keysCreated, keysTotal ); // TODO: default to one master for cert, one sub for encrypt and one sub // for sign diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 898b0e67a..2507a77b1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -187,7 +187,7 @@ public class EditKeyActivity extends ActionBarActivity { // Message is received after generating is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( - this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER, true, + this, R.string.progress_generating, ProgressDialog.STYLE_HORIZONTAL, true, new DialogInterface.OnCancelListener() { @Override diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index b486fc151..665035d0c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -52,17 +52,21 @@ import android.os.Message; import android.os.Messenger; import android.view.View; import android.view.View.OnClickListener; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; import com.beardedhen.androidbootstrap.BootstrapButton; +import com.beardedhen.androidbootstrap.FontAwesomeText; import com.devspark.appmsg.AppMsg; public class EncryptActivity extends DrawerActivity { @@ -114,6 +118,11 @@ public class EncryptActivity extends DrawerActivity { private String mInputFilename = null; private String mOutputFilename = null; + private Integer mShortAnimationDuration = null; + private boolean mFileAdvancedSettingsVisible = false; + private TextView mFileAdvancedSettings = null; + private LinearLayout mFileAdvancedSettingsContainer = null; + private FontAwesomeText mAdvancedSettingsIcon; private boolean mAsciiArmorDemand = false; private boolean mOverrideAsciiArmor = false; @@ -148,6 +157,9 @@ public class EncryptActivity extends DrawerActivity { updateMode(); updateActionBarButtons(); + + // retrieve and cache the system's short animation time + mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); } /** @@ -793,6 +805,50 @@ public class EncryptActivity extends DrawerActivity { } }); + mAdvancedSettingsIcon = (FontAwesomeText) findViewById(R.id.advancedSettingsIcon); + mFileAdvancedSettingsContainer = (LinearLayout) findViewById(R.id.fileAdvancedSettingsContainer); + mFileAdvancedSettings = (TextView) findViewById(R.id.advancedSettings); + + LinearLayout advancedSettingsControl = (LinearLayout) findViewById(R.id.advancedSettingsControl); + advancedSettingsControl.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mFileAdvancedSettingsVisible = !mFileAdvancedSettingsVisible; + if (mFileAdvancedSettingsVisible) { + mAdvancedSettingsIcon.setIcon("fa-chevron-down"); + mFileAdvancedSettingsContainer.setVisibility(View.VISIBLE); + AlphaAnimation animation = new AlphaAnimation(0f, 1f); + animation.setDuration(mShortAnimationDuration); + mFileAdvancedSettingsContainer.startAnimation(animation); + mFileAdvancedSettings.setText(R.string.btn_encryption_advanced_settings_hide); + + } else { + mAdvancedSettingsIcon.setIcon("fa-chevron-right"); + AlphaAnimation animation = new AlphaAnimation(1f, 0f); + animation.setDuration(mShortAnimationDuration); + animation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + // do nothing + } + + @Override + public void onAnimationEnd(Animation animation) { + // making sure that at the end the container is completely removed from view + mFileAdvancedSettingsContainer.setVisibility(View.GONE); + } + + @Override + public void onAnimationRepeat(Animation animation) { + // do nothing + } + }); + mFileAdvancedSettingsContainer.startAnimation(animation); + mFileAdvancedSettings.setText(R.string.btn_encryption_advanced_settings_show); + } + } + }); + mFileCompression = (Spinner) findViewById(R.id.fileCompression); Choice[] choices = new Choice[]{ new Choice(Id.choice.compression.none, getString(R.string.choice_none) + " (" diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 5ac421a44..7e31d795e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -161,7 +161,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa } else if (extras.containsKey(EXTRA_KEY_ID)) { long keyId = intent.getLongExtra(EXTRA_KEY_ID, 0); if (keyId != 0) { - query = "0x" + PgpKeyHelper.convertKeyToHex(keyId); + query = PgpKeyHelper.convertKeyIdToHex(keyId); } } else if (extras.containsKey(EXTRA_FINGERPRINT)) { String fingerprint = intent.getStringExtra(EXTRA_FINGERPRINT); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 1118f0264..a6917d6f4 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -219,27 +219,44 @@ public class ImportKeysListFragment extends ListFragment implements } else { setListShownNoAnimation(true); } + + Exception error = data.getError(); + switch (loader.getId()) { case LOADER_ID_BYTES: + + if(error == null){ + // No error + } else if(error instanceof ImportKeysListLoader.FileHasNoContent) { + AppMsg.makeText(getActivity(), R.string.error_import_file_no_content, + AppMsg.STYLE_ALERT).show(); + } else if(error instanceof ImportKeysListLoader.NonPgpPart) { + AppMsg.makeText(getActivity(), + ((ImportKeysListLoader.NonPgpPart) error).getCount() + " " + getResources(). + getQuantityString(R.plurals.error_import_non_pgp_part, + ((ImportKeysListLoader.NonPgpPart) error).getCount()), + new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.confirm)).show(); + } else { + AppMsg.makeText(getActivity(), R.string.error_generic_report_bug, + new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.alert)).show(); + } break; case LOADER_ID_SERVER_QUERY: - Exception error = data.getError(); - - if(error == null){ + if(error == null) { AppMsg.makeText( getActivity(), getResources().getQuantityString(R.plurals.keys_found, mAdapter.getCount(), mAdapter.getCount()), AppMsg.STYLE_INFO ).show(); - } else if(error instanceof KeyServer.InsufficientQuery){ + } else if(error instanceof KeyServer.InsufficientQuery) { AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query, AppMsg.STYLE_ALERT).show(); - }else if(error instanceof KeyServer.QueryException){ + } else if(error instanceof KeyServer.QueryException) { AppMsg.makeText(getActivity(), R.string.error_keyserver_query, AppMsg.STYLE_ALERT).show(); - }else if(error instanceof KeyServer.TooManyResponses){ + } else if(error instanceof KeyServer.TooManyResponses) { AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses, AppMsg.STYLE_ALERT).show(); } 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 f14fadd77..c2b21027c 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 @@ -171,15 +171,8 @@ public class KeyListPublicFragment extends Fragment implements SearchView.OnQuer @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - Set<Integer> positions = mAdapter.getCurrentCheckedPosition(); - - // get IDs for checked positions as long array - long[] ids = new long[positions.size()]; - int i = 0; - for (int pos : positions) { - ids[i] = mAdapter.getItemId(pos); - i++; - } + // get row ids for checked positions as long array + long[] ids = mStickyList.getCheckedItemIds(); switch (item.getItemId()) { case R.id.menu_key_list_public_multi_encrypt: { @@ -192,9 +185,8 @@ public class KeyListPublicFragment extends Fragment implements SearchView.OnQuer } 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); + for (int i = 0; i < mStickyList.getCount(); i++) { + mStickyList.setItemChecked(i, true); } break; } @@ -215,7 +207,7 @@ public class KeyListPublicFragment extends Fragment implements SearchView.OnQuer } else { mAdapter.removeSelection(position); } - int count = mAdapter.getCurrentCheckedPosition().size(); + int count = mStickyList.getCheckedItemCount(); String keysSelected = getResources().getQuantityString( R.plurals.key_list_selected_keys, count, count); mode.setTitle(keysSelected); @@ -272,8 +264,8 @@ public class KeyListPublicFragment extends Fragment implements SearchView.OnQuer public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) + mAdapter.setSearchQuery(mCurQuery); mAdapter.swapCursor(data); - mStickyList.setAdapter(mAdapter); // NOTE: Not supported by StickyListHeader, but reimplemented here @@ -375,6 +367,7 @@ public class KeyListPublicFragment extends Fragment implements SearchView.OnQuer // Execute this when searching mSearchView.setOnQueryTextListener(this); + super.onCreateOptionsMenu(menu, inflater); } 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 9a5477762..76212afc3 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 @@ -91,15 +91,8 @@ public class KeyListSecretFragment extends ListFragment implements @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - Set<Integer> positions = mAdapter.getCurrentCheckedPosition(); - - // get IDs for checked positions as long array - long[] ids = new long[positions.size()]; - int i = 0; - for (int pos : positions) { - ids[i] = mAdapter.getItemId(pos); - i++; - } + // get row ids for checked positions as long array + long[] ids = getListView().getCheckedItemIds(); switch (item.getItemId()) { case R.id.menu_key_list_public_multi_delete: { @@ -108,9 +101,8 @@ public class KeyListSecretFragment extends ListFragment implements } 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); + for (int i = 0; i < getListView().getCount(); i++) { + getListView().setItemChecked(i, true); } break; } 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 6e338979a..c1c9aa705 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 @@ -311,6 +311,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) + mAdapter.setSearchQuery(mCurQuery); mAdapter.swapCursor(data); // The list should now be shown. diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 2db5fc27f..390de9ab9 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -154,7 +154,7 @@ public class ViewKeyActivity extends ActionBarActivity { } private void updateFromKeyserver(Uri dataUri) { - long updateKeyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, mDataUri); + long updateKeyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, dataUri); if (updateKeyId == 0) { Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 495764eaf..65fe08484 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -19,13 +19,17 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.database.Cursor; +import android.graphics.Color; import android.net.Uri; import android.os.Bundle; 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.text.Spannable; +import android.text.SpannableStringBuilder; import android.text.format.DateFormat; +import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -225,7 +229,7 @@ public class ViewKeyMainFragment extends Fragment implements // get key id from MASTER_KEY_ID long keyId = data.getLong(KEYS_INDEX_KEY_ID); - String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(keyId); mKeyId.setText(keyIdStr); // get creation date from CREATION @@ -258,9 +262,8 @@ public class ViewKeyMainFragment extends Fragment implements fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), mDataUri); } String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, true); - fingerprint = fingerprint.replace(" ", "\n"); - mFingerprint.setText(fingerprint); + mFingerprint.setText(colorizeFingerprint(fingerprint)); } mKeysAdapter.swapCursor(data); @@ -271,6 +274,24 @@ public class ViewKeyMainFragment extends Fragment implements } } + private SpannableStringBuilder colorizeFingerprint(String fingerprint) { + SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint); + ForegroundColorSpan fcs = new ForegroundColorSpan(Color.BLACK); + + // for each 4 characters of the fingerprint + 1 space + for (int i = 0; i < fingerprint.length(); i += 5) { + String fourChars = fingerprint.substring(i, Math.min(i + 4, fingerprint.length())); + + // Create a foreground color by converting the 4 fingerprint chars to an int hashcode + // and then converting that int to hex to use as a color + fcs = new ForegroundColorSpan( + Color.parseColor(String.format("#%06X", (0xFFFFFF & fourChars.hashCode())))); + sb.setSpan(fcs, i, Math.min(i+4, fingerprint.length()), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + + return sb; + } + /** * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. * We need to make sure we are no longer using it. diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java new file mode 100644 index 000000000..fd7a2dc30 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui.adapter; + +import android.content.Context; +import android.database.Cursor; +import android.support.v4.widget.CursorAdapter; +import android.text.Spannable; +import android.text.style.ForegroundColorSpan; + +import org.sufficientlysecure.keychain.R; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class HighlightQueryCursorAdapter extends CursorAdapter { + + private String mCurQuery; + + public HighlightQueryCursorAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + mCurQuery = null; + } + + public void setSearchQuery(String searchQuery) { + mCurQuery = searchQuery; + } + + public String getSearchQuery() { + return mCurQuery; + } + + protected Spannable highlightSearchQuery(String text) { + Spannable highlight = Spannable.Factory.getInstance().newSpannable(text); + + if (mCurQuery != null) { + Pattern pattern = Pattern.compile("(?i)" + mCurQuery); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + highlight.setSpan( + new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)), + matcher.start(), + matcher.end(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return highlight; + } else { + return highlight; + } + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java index 01b6deeaa..a52e9b447 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java @@ -125,7 +125,10 @@ public class ImportKeysListEntry implements Serializable, Parcelable { * Constructor for later querying from keyserver */ public ImportKeysListEntry() { + // keys from keyserver are always public keys secretKey = false; + // do not select by default + selected = false; userIds = new ArrayList<String>(); } @@ -152,7 +155,9 @@ public class ImportKeysListEntry implements Serializable, Parcelable { // selected is default this.selected = true; - if ( !(pgpKeyRing instanceof PGPSecretKeyRing) ) { + if (pgpKeyRing instanceof PGPSecretKeyRing) { + secretKey = true; + } else { secretKey = false; } @@ -165,7 +170,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { this.revoked = pgpKeyRing.getPublicKey().isRevoked(); this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() .getFingerprint(), true); - this.hexKeyId = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); + this.hexKeyId = PgpKeyHelper.convertKeyIdToHex(keyId); this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength(); int algorithm = pgpKeyRing.getPublicKey().getAlgorithm(); if (algorithm == PGPPublicKey.RSA_ENCRYPT || algorithm == PGPPublicKey.RSA_GENERAL diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 357f5a3f1..3eca99f15 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -33,6 +33,21 @@ import android.content.Context; import android.support.v4.content.AsyncTaskLoader; public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { + + public static class FileHasNoContent extends Exception { + + } + + public static class NonPgpPart extends Exception { + private int count; + public NonPgpPart(int count) { + this.count = count; + } + public int getCount() { + return count; + } + } + Context mContext; InputData mInputData; @@ -91,6 +106,10 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper * @return */ private void generateListOfKeyrings(InputData inputData) { + + boolean isEmpty = true; + int nonPgpCounter = 0; + PositionAwareInputStream progressIn = new PositionAwareInputStream( inputData.getInputStream()); @@ -102,6 +121,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper // read all available blocks... (asc files can contain many blocks with BEGIN END) while (bufferedInput.available() > 0) { + isEmpty = false; InputStream in = PGPUtil.getDecoderStream(bufferedInput); PGPObjectFactory objectFactory = new PGPObjectFactory(in); @@ -115,11 +135,25 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper addToData(newKeyring); } else { Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); + nonPgpCounter++; } } } } catch (Exception e) { Log.e(Constants.TAG, "Exception on parsing key file!", e); + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, e); + nonPgpCounter = 0; + } + + if(isEmpty) { + Log.e(Constants.TAG, "File has no content!", new FileHasNoContent()); + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> + (data, new FileHasNoContent()); + } + + if(nonPgpCounter > 0) { + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> + (data, new NonPgpPart(nonPgpCounter)); } } 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 086d2c178..b8f60633e 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 @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui.adapter; import java.util.HashMap; import java.util.Set; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; @@ -32,7 +33,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.database.Cursor; import android.graphics.Color; -import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -41,7 +41,7 @@ import android.widget.TextView; /** * Implements StickyListHeadersAdapter from library */ -public class KeyListPublicAdapter extends CursorAdapter implements StickyListHeadersAdapter { +public class KeyListPublicAdapter extends HighlightQueryCursorAdapter implements StickyListHeadersAdapter { private LayoutInflater mInflater; private int mSectionColumnIndex; private int mIndexUserId; @@ -52,7 +52,6 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea public KeyListPublicAdapter(Context context, Cursor c, int flags, int sectionColumnIndex) { super(context, c, flags); - mInflater = LayoutInflater.from(context); mSectionColumnIndex = sectionColumnIndex; initIndex(c); @@ -93,12 +92,12 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea String userId = cursor.getString(mIndexUserId); String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[0] != null) { - mainUserId.setText(userIdSplit[0]); + mainUserId.setText(highlightSearchQuery(userIdSplit[0])); } else { mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); + mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); mainUserIdRest.setVisibility(View.VISIBLE); } else { mainUserIdRest.setVisibility(View.GONE); @@ -193,15 +192,6 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea notifyDataSetChanged(); } - public boolean isPositionChecked(int position) { - Boolean result = mSelection.get(position); - return result == null ? false : result; - } - - public Set<Integer> getCurrentCheckedPosition() { - return mSelection.keySet(); - } - public void removeSelection(int position) { mSelection.remove(position); notifyDataSetChanged(); @@ -220,11 +210,12 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea /** * Change color for multi-selection */ - // default color - v.setBackgroundColor(Color.TRANSPARENT); if (mSelection.get(position) != null && mSelection.get(position).booleanValue()) { - // this is a selected position, change color! + // color for selected items v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); + } else { + // default color + v.setBackgroundColor(Color.TRANSPARENT); } return v; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java index 11d1e8c17..ca3a26066 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -98,16 +98,7 @@ public class KeyListSecretAdapter extends CursorAdapter { mSelection.put(position, value); notifyDataSetChanged(); } - - public boolean isPositionChecked(int position) { - Boolean result = mSelection.get(position); - return result == null ? false : result; - } - - public Set<Integer> getCurrentCheckedPosition() { - return mSelection.keySet(); - } - + public void removeSelection(int position) { mSelection.remove(position); notifyDataSetChanged(); @@ -126,11 +117,12 @@ public class KeyListSecretAdapter extends CursorAdapter { /** * Change color for multi-selection */ - // default color - v.setBackgroundColor(Color.TRANSPARENT); if (mSelection.get(position) != null) { - // this is a selected position, change color! + // color for selected items v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); + } else { + // default color + v.setBackgroundColor(Color.TRANSPARENT); } return v; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index d44dd5890..6d67a0e65 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -25,7 +25,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import android.content.Context; import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -33,7 +32,9 @@ import android.widget.CheckBox; import android.widget.ListView; import android.widget.TextView; -public class SelectKeyCursorAdapter extends CursorAdapter { + + +public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter { protected int mKeyType; @@ -55,7 +56,6 @@ public class SelectKeyCursorAdapter extends CursorAdapter { mInflater = LayoutInflater.from(context); mListView = listView; mKeyType = keyType; - initIndex(c); } @@ -104,12 +104,12 @@ public class SelectKeyCursorAdapter extends CursorAdapter { String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[0] != null) { - mainUserId.setText(userIdSplit[0]); + mainUserId.setText(highlightSearchQuery(userIdSplit[0])); } else { mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); + mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); } else { mainUserIdRest.setText(""); } @@ -164,5 +164,4 @@ public class SelectKeyCursorAdapter extends CursorAdapter { public View newView(Context context, Cursor cursor, ViewGroup parent) { return mInflater.inflate(R.layout.select_key_item, null); } - } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java index 54c7eb60e..046a98883 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java @@ -83,7 +83,7 @@ public class ViewKeyKeysAdapter extends CursorAdapter { ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); - String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm), cursor.getInt(mIndexKeySize)); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index f1516faaa..9f25fac42 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -176,9 +176,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(key)); - String keyId1Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID()); - String keyId2Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID() >> 32); - mKeyId.setText(keyId1Str + " " + keyId2Str); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(key.getKeyID()); + mKeyId.setText(keyIdStr); Vector<Choice> choices = new Vector<Choice>(); boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java index 921d22f21..0681847f4 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java @@ -226,7 +226,7 @@ public class HkpKeyServer extends KeyServer { HttpClient client = new DefaultHttpClient(); try { HttpGet get = new HttpGet("http://" + mHost + ":" + mPort - + "/pks/lookup?op=get&search=0x" + PgpKeyHelper.convertKeyToHex(keyId)); + + "/pks/lookup?op=get&search=0x" + PgpKeyHelper.convertKeyIdToHex(keyId)); HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { diff --git a/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml index e716b033a..dc4cf0063 100644 --- a/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto" + xmlns:fontawesometext="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> @@ -251,64 +252,97 @@ </LinearLayout> <LinearLayout + android:id="@+id/advancedSettingsControl" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> - - <TextView - android:id="@+id/label_fileCompression" - android:layout_width="0dip" + android:orientation="horizontal" + android:clickable="true"> + <com.beardedhen.androidbootstrap.FontAwesomeText + android:id="@+id/advancedSettingsIcon" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_weight="1" - android:paddingRight="10dip" - android:text="@string/label_file_compression" - android:textAppearance="?android:attr/textAppearanceSmall" /> - - <Spinner - android:id="@+id/fileCompression" + android:layout_marginRight="10dp" + android:textSize="12sp" + android:paddingTop="@dimen/padding_medium" + android:paddingBottom="@dimen/padding_medium" + fontawesometext:fa_icon="fa-chevron-right"/> + <TextView + android:id="@+id/advancedSettings" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" /> + android:text="@string/btn_encryption_advanced_settings_show" + android:paddingTop="@dimen/padding_medium" + android:paddingBottom="@dimen/padding_medium" + android:textColor="@color/emphasis"/> </LinearLayout> <LinearLayout + android:id="@+id/fileAdvancedSettingsContainer" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> + android:orientation="vertical" + android:visibility="gone"> - <CheckBox - android:id="@+id/deleteAfterEncryption" - android:layout_width="wrap_content" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:text="@string/label_delete_after_encryption" /> - </LinearLayout> + android:orientation="horizontal"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> + <TextView + android:id="@+id/label_fileCompression" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:paddingRight="10dip" + android:text="@string/label_file_compression" + android:textAppearance="?android:attr/textAppearanceSmall" /> - <CheckBox - android:id="@+id/shareAfterEncryption" - android:layout_width="wrap_content" + <Spinner + android:id="@+id/fileCompression" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:text="@string/label_share_after_encryption" /> - </LinearLayout> + android:orientation="horizontal"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> + <CheckBox + android:id="@+id/deleteAfterEncryption" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/label_delete_after_encryption" /> + </LinearLayout> - <CheckBox - android:id="@+id/asciiArmour" - android:layout_width="wrap_content" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:text="@string/label_ascii_armor" /> + android:orientation="horizontal"> + + <CheckBox + android:id="@+id/shareAfterEncryption" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/label_share_after_encryption" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <CheckBox + android:id="@+id/asciiArmour" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/label_ascii_armor" /> + </LinearLayout> </LinearLayout> </LinearLayout> </ViewFlipper> diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml index 055687183..b44ca82ec 100644 --- a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml @@ -92,7 +92,7 @@ android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" - android:stretchColumns="1"> + android:shrinkColumns="1"> <TableRow> 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 35a8f3926..35f4fca92 100644 --- a/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml +++ b/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml @@ -4,7 +4,7 @@ <item android:id="@+id/menu_key_list_public_import" - app:showAsAction="always|withText" + app:showAsAction="ifRoom|withText" android:icon="@drawable/ic_action_add_person" android:title="@string/menu_import" /> <item @@ -16,5 +16,5 @@ android:title="@string/menu_search" android:icon="@drawable/ic_action_search" app:actionViewClass="android.support.v7.widget.SearchView" - app:showAsAction="ifRoom" /> + app:showAsAction="collapseActionView|ifRoom" /> </menu>
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml index ec4a45b3e..7f53fd0e4 100644 --- a/OpenPGP-Keychain/src/main/res/values/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values/strings.xml @@ -67,6 +67,8 @@ <string name="btn_clipboard">Clipboard</string> <string name="btn_share">Share with…</string> <string name="btn_lookup_key">Lookup key</string> + <string name="btn_encryption_advanced_settings_show">Show advanced settings</string> + <string name="btn_encryption_advanced_settings_hide">Hide advanced settings</string> <!-- menu --> <string name="menu_preferences">Settings</string> @@ -296,10 +298,16 @@ <string name="error_keyserver_insufficient_query">Insufficient server query</string> <string name="error_keyserver_query">Querying keyserver failed</string> <string name="error_keyserver_too_many_responses">Too many responses</string> + <string name="error_import_file_no_content">File has no content</string> + <string name="error_generic_report_bug">A generic error occurred, please create a new bug report for OpenKeychain.</string> <plurals name="error_can_not_delete_info"> <item quantity="one">Please delete it from the \'My Keys\' screen!</item> <item quantity="other">Please delete them from the \'My Keys\' screen!</item> </plurals> + <plurals name="error_import_non_pgp_part"> + <item quantity="one">part of the loaded file is a valid OpenPGP object but not a OpenPGP key</item> + <item quantity="other">parts of the loaded file are valid OpenPGP objects but not OpenPGP keys</item> + </plurals> <!-- progress dialogs, usually ending in '…' --> <string name="progress_done">Done.</string> @@ -307,7 +315,6 @@ <string name="progress_saving">saving…</string> <string name="progress_importing">importing…</string> <string name="progress_exporting">exporting…</string> - <string name="progress_generating">generating key, this can take up to 3 minutes…</string> <string name="progress_building_key">building key…</string> <string name="progress_preparing_master_key">preparing master key…</string> <string name="progress_certifying_master_key">certifying master key…</string> @@ -320,6 +327,11 @@ <item quantity="other">exporting keys…</item> </plurals> + <plurals name="progress_generating"> + <item quantity="one">generating key, this can take up to 3 minutes…</item> + <item quantity="other">generating keys, this can take up to 3 minutes…</item> + </plurals> + <string name="progress_extracting_signature_key">extracting signature key…</string> <string name="progress_extracting_key">extracting key…</string> <string name="progress_preparing_streams">preparing streams…</string> |