From 555b0bf7573a9273bdd5e8c7870cabd8cd0e2186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 18 Apr 2015 16:50:52 +0200 Subject: Temporarily fix devices without nfc --- .../org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 95c1690b1..db7aba519 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -476,6 +476,9 @@ public abstract class BaseNfcActivity extends BaseActivity { */ public void enableNfcForegroundDispatch() { mNfcAdapter = NfcAdapter.getDefaultAdapter(this); + if (mNfcAdapter == null) { + return; + } Intent nfcI = new Intent(this, getClass()) .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT); @@ -497,6 +500,9 @@ public abstract class BaseNfcActivity extends BaseActivity { * Disable foreground dispatch in onPause! */ public void disableNfcForegroundDispatch() { + if (mNfcAdapter == null) { + return; + } mNfcAdapter.disableForegroundDispatch(this); Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!"); } -- cgit v1.2.3 From f2d3abd4c9cd521754d932a057356b511247be00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 18 Apr 2015 16:52:02 +0200 Subject: Format KeyListFragment --- .../keychain/ui/KeyListFragment.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 4733dce01..96ce101b5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -681,17 +681,16 @@ public class KeyListFragment extends LoaderFragment } private void showMultiExportDialog(long[] masterKeyIds) { - mIdsForRepeatAskPassphrase = new ArrayList(); - for(long id: masterKeyIds) { + mIdsForRepeatAskPassphrase = new ArrayList<>(); + for (long id : masterKeyIds) { try { if (PassphraseCacheService.getCachedPassphrase( getActivity(), id, id) == null) { - mIdsForRepeatAskPassphrase.add(Long.valueOf(id)); + mIdsForRepeatAskPassphrase.add(id); } } catch (PassphraseCacheService.KeyNotFoundException e) { // This happens when the master key is stripped // and ignore this key. - continue; } } mIndex = 0; @@ -700,8 +699,8 @@ public class KeyListFragment extends LoaderFragment return; } long[] idsForMultiExport = new long[mIdsForRepeatAskPassphrase.size()]; - for(int i=0; i Date: Mon, 20 Apr 2015 13:53:00 +0200 Subject: Cleanup in HkpKeyserver --- .../org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index 480319081..cb8a53e25 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -242,7 +242,7 @@ public class HkpKeyserver extends Keyserver { String encodedQuery; try { - encodedQuery = URLEncoder.encode(query, "utf8"); + encodedQuery = URLEncoder.encode(query, "UTF8"); } catch (UnsupportedEncodingException e) { return null; } @@ -286,7 +286,7 @@ public class HkpKeyserver extends Keyserver { entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitSize, null)); // group 1 contains the full fingerprint (v4) or the long key id if available - // see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr + // see https://bitbucket.org/skskeyserver/sks-keyserver/pull-request/12/fixes-for-machine-readable-indexes/diff String fingerprintOrKeyId = matcher.group(1).toLowerCase(Locale.ENGLISH); if (fingerprintOrKeyId.length() > 16) { entry.setFingerprintHex(fingerprintOrKeyId); @@ -312,14 +312,13 @@ public class HkpKeyserver extends Keyserver { String tmp = uidMatcher.group(1).trim(); if (tmp.contains("%")) { if (tmp.contains("%%")) { - // This is a fix for issue #683 // The server encodes a percent sign as %%, so it is swapped out with its // urlencoded counterpart to prevent errors tmp = tmp.replace("%%", "%25"); } try { // converts Strings like "Universit%C3%A4t" to a proper encoding form "Universität". - tmp = (URLDecoder.decode(tmp, "UTF8")); + tmp = URLDecoder.decode(tmp, "UTF8"); } catch (UnsupportedEncodingException ignored) { // will never happen, because "UTF8" is supported } -- cgit v1.2.3 From 91443c2f43615f25cd412007d89fe5a8ccc082bb Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Sun, 19 Apr 2015 13:31:37 +0530 Subject: support for handling keyserver urls from browser, added documentation --- OpenKeychain/src/main/AndroidManifest.xml | 17 ++++ .../keychain/ui/CreateKeyYubiImportFragment.java | 3 +- .../keychain/ui/ImportKeysActivity.java | 93 +++++++++++++++++----- .../keychain/ui/ImportKeysCloudFragment.java | 23 +++++- .../keychain/ui/ImportKeysListFragment.java | 56 ++++++++++--- .../keychain/ui/adapter/ImportKeysListLoader.java | 4 +- .../keychain/util/Preferences.java | 5 ++ OpenKeychain/src/main/res/values/strings.xml | 3 + 8 files changed, 167 insertions(+), 37 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index d0f50d5cc..8c66176fd 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -624,6 +624,23 @@ + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java index 1cd0aaf2f..db62d53c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java @@ -123,7 +123,8 @@ public class CreateKeyYubiImportFragment extends Fragment implements NfcListener }); } - mListFragment = ImportKeysListFragment.newInstance(null, null, "0x" + mNfcFingerprint, true); + mListFragment = ImportKeysListFragment.newInstance(null, null, + "0x" + mNfcFingerprint, true, null); view.findViewById(R.id.button_search).setOnClickListener(new OnClickListener() { @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 7fe5be793..5d9950db6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -39,6 +39,7 @@ import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.service.CloudImportService; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; +import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; @@ -62,6 +63,8 @@ public class ImportKeysActivity extends BaseNfcActivity { // Actions for internal use only: public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_FILE"; + public static final String ACTION_SEARCH_KEYSERVER_FROM_URL = Constants.INTENT_PREFIX + + "SEARCH_KEYSERVER_FROM_URL"; public static final String EXTRA_RESULT = "result"; // only used by ACTION_IMPORT_KEY @@ -112,15 +115,19 @@ public class ImportKeysActivity extends BaseNfcActivity { } if (action == null) { - startCloudFragment(savedInstanceState, null, false); - startListFragment(savedInstanceState, null, null, null); + startCloudFragment(savedInstanceState, null, false, null); + startListFragment(savedInstanceState, null, null, null, null); return; } if (Intent.ACTION_VIEW.equals(action)) { - // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) - // delegate action to ACTION_IMPORT_KEY - action = ACTION_IMPORT_KEY; + if (scheme.equals("http") || scheme.equals("https")) { + action = ACTION_SEARCH_KEYSERVER_FROM_URL; + } else { + // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) + // delegate action to ACTION_IMPORT_KEY + action = ACTION_IMPORT_KEY; + } } switch (action) { @@ -130,12 +137,12 @@ public class ImportKeysActivity extends BaseNfcActivity { if (dataUri != null) { // action: directly load data - startListFragment(savedInstanceState, null, dataUri, null); + startListFragment(savedInstanceState, null, dataUri, null, null); } else if (extras.containsKey(EXTRA_KEY_BYTES)) { byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES); // action: directly load data - startListFragment(savedInstanceState, importData, null, null); + startListFragment(savedInstanceState, importData, null, null, null); } break; } @@ -162,10 +169,10 @@ public class ImportKeysActivity extends BaseNfcActivity { if (query != null && query.length() > 0) { // display keyserver fragment with query - startCloudFragment(savedInstanceState, query, false); + startCloudFragment(savedInstanceState, query, false, null); // action: search immediately - startListFragment(savedInstanceState, null, null, query); + startListFragment(savedInstanceState, null, null, query, null); } else { Log.e(Constants.TAG, "Query is empty!"); return; @@ -181,10 +188,10 @@ public class ImportKeysActivity extends BaseNfcActivity { String query = "0x" + fingerprint; // display keyserver fragment with query - startCloudFragment(savedInstanceState, query, true); + startCloudFragment(savedInstanceState, query, true, null); // action: search immediately - startListFragment(savedInstanceState, null, null, query); + startListFragment(savedInstanceState, null, null, query, null); } } else { Log.e(Constants.TAG, @@ -200,7 +207,29 @@ public class ImportKeysActivity extends BaseNfcActivity { startFileFragment(savedInstanceState); // no immediate actions! - startListFragment(savedInstanceState, null, null, null); + startListFragment(savedInstanceState, null, null, null, null); + break; + } + case ACTION_SEARCH_KEYSERVER_FROM_URL: { + // need to process URL to get search query and keyserver authority + String query = dataUri.getQueryParameter("search"); + String keyserver = dataUri.getAuthority(); + // if query not specified, we still allow users to search the keyserver in the link + if (query == null) { + Notify.create(this, R.string.import_url_warn_no_search_parameter, Notify.LENGTH_INDEFINITE, + Notify.Style.WARN).show(mTopFragment); + // we just set the keyserver + startCloudFragment(savedInstanceState, null, false, keyserver); + // it's not necessary to set the keyserver for ImportKeysListFragment since + // it'll be taken care of by ImportKeysCloudFragment when the user clicks + // the search button + startListFragment(savedInstanceState, null, null, null, null); + } else { + // we allow our users to edit the query if they wish + startCloudFragment(savedInstanceState, query, false, keyserver); + // search immediately + startListFragment(savedInstanceState, null, null, query, keyserver); + } break; } case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: { @@ -208,18 +237,31 @@ public class ImportKeysActivity extends BaseNfcActivity { startFileFragment(savedInstanceState); // no immediate actions! - startListFragment(savedInstanceState, null, null, null); + startListFragment(savedInstanceState, null, null, null, null); break; } default: { - startCloudFragment(savedInstanceState, null, false); - startListFragment(savedInstanceState, null, null, null); + startCloudFragment(savedInstanceState, null, false, null); + startListFragment(savedInstanceState, null, null, null, null); break; } } } - private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, String serverQuery) { + + /** + * if the fragment is started with non-null bytes/dataUri/serverQuery, it will immediately + * load content + * + * @param savedInstanceState + * @param bytes bytes containing list of keyrings to import + * @param dataUri uri to file to import keyrings from + * @param serverQuery query to search for on the keyserver + * @param keyserver keyserver authority to search on. If null will use keyserver from + * user preferences + */ + private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, + String serverQuery, String keyserver) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else // we could end up with overlapping fragments. @@ -227,8 +269,8 @@ public class ImportKeysActivity extends BaseNfcActivity { return; } - // Create an instance of the fragment - mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery); + mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery, false, + keyserver); // Add the fragment to the 'fragment_container' FrameLayout // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! @@ -259,7 +301,18 @@ public class ImportKeysActivity extends BaseNfcActivity { getSupportFragmentManager().executePendingTransactions(); } - private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit) { + /** + * loads the CloudFragment, which consists of the search bar, search button and settings icon + * visually. + * + * @param savedInstanceState + * @param query search query + * @param disableQueryEdit if true, user will not be able to edit the search query + * @param keyserver keyserver authority to use for search, if null will use keyserver + * specified in user preferences + */ + + private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit, String keyserver) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else // we could end up with overlapping fragments. @@ -268,7 +321,7 @@ public class ImportKeysActivity extends BaseNfcActivity { } // Create an instance of the fragment - mTopFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit); + mTopFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit, keyserver); // Add the fragment to the 'fragment_container' FrameLayout // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java index 91ca93c36..1cd5c24f3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -45,6 +45,7 @@ import java.util.List; public class ImportKeysCloudFragment extends Fragment { public static final String ARG_QUERY = "query"; public static final String ARG_DISABLE_QUERY_EDIT = "disable_query_edit"; + public static final String ARG_KEYSERVER = "keyserver"; private ImportKeysActivity mImportActivity; @@ -54,13 +55,20 @@ public class ImportKeysCloudFragment extends Fragment { /** * Creates new instance of this fragment + * + * @param query query to search for + * @param disableQueryEdit if true, user cannot edit query + * @param keyserver specified keyserver authority to use. If null, will use keyserver + * specified in user preferences */ - public static ImportKeysCloudFragment newInstance(String query, boolean disableQueryEdit) { + public static ImportKeysCloudFragment newInstance(String query, boolean disableQueryEdit, + String keyserver) { ImportKeysCloudFragment frag = new ImportKeysCloudFragment(); Bundle args = new Bundle(); args.putString(ARG_QUERY, query); args.putBoolean(ARG_DISABLE_QUERY_EDIT, disableQueryEdit); + args.putString(ARG_KEYSERVER, keyserver); frag.setArguments(args); @@ -151,8 +159,17 @@ public class ImportKeysCloudFragment extends Fragment { } private void search(String query) { - Preferences prefs = Preferences.getPreferences(getActivity()); - mImportActivity.loadCallback(new ImportKeysListFragment.CloudLoaderState(query, prefs.getCloudSearchPrefs())); + Preferences.CloudSearchPrefs cloudSearchPrefs; + String explicitKeyserver = getArguments().getString(ARG_KEYSERVER); + // no explicit keyserver passed + if (explicitKeyserver == null) { + cloudSearchPrefs = Preferences.getPreferences(getActivity()).getCloudSearchPrefs(); + } else { + // assume we are also meant to search keybase.io + cloudSearchPrefs = new Preferences.CloudSearchPrefs(true, true, explicitKeyserver); + } + mImportActivity.loadCallback( + new ImportKeysListFragment.CloudLoaderState(query, cloudSearchPrefs)); toggleKeyboard(false); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index b9fdbea5c..81ff87216 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -58,6 +58,7 @@ public class ImportKeysListFragment extends ListFragment implements private static final String ARG_BYTES = "bytes"; public static final String ARG_SERVER_QUERY = "query"; public static final String ARG_NON_INTERACTIVE = "non_interactive"; + public static final String ARG_KEYSERVER_URL = "keyserver_url"; private Activity mActivity; private ImportKeysAdapter mAdapter; @@ -78,7 +79,8 @@ public class ImportKeysListFragment extends ListFragment implements return mAdapter.getData(); } - /** Returns an Iterator (with size) of the selected data items. + /** + * Returns an Iterator (with size) of the selected data items. * This iterator is sort of a tradeoff, it's slightly more complex than an * ArrayList would have been, but we save some memory by just returning * relevant elements on demand. @@ -121,12 +123,36 @@ public class ImportKeysListFragment extends ListFragment implements } - public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery) { - return newInstance(bytes, dataUri, serverQuery, false); + /** + * Creates an interactive ImportKeyListFragment which reads keyrings from bytes, or file specified + * by dataUri, or searches a keyserver for serverQuery, if parameter is not null, in that order + * + * @param bytes byte data containing list of keyrings to be imported + * @param dataUri file from which keyrings are to be imported + * @param serverQuery query to search for on keyserver + * @param keyserver if not null, will perform search on specified keyserver. Else, uses + * keyserver specified in user preferences + * @return fragment with arguments set based on passed parameters + */ + public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery, + String keyserver) { + return newInstance(bytes, dataUri, serverQuery, false, keyserver); } - public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, - String serverQuery, boolean nonInteractive) { + /** + * Visually consists of a list of keyrings with checkboxes to specify which are to be imported + * Can immediately load keyrings specified by any of its parameters + * + * @param bytes byte data containing list of keyrings to be imported + * @param dataUri file from which keyrings are to be imported + * @param serverQuery query to search for on keyserver + * @param nonInteractive if true, users will not be able to check/uncheck items in the list + * @param keyserver if set, will perform search on specified keyserver. If null, falls back + * to keyserver specified in user preferences + * @return fragment with arguments set based on passed parameters + */ + public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery, + boolean nonInteractive, String keyserver) { ImportKeysListFragment frag = new ImportKeysListFragment(); Bundle args = new Bundle(); @@ -134,6 +160,7 @@ public class ImportKeysListFragment extends ListFragment implements args.putParcelable(ARG_DATA_URI, dataUri); args.putString(ARG_SERVER_QUERY, serverQuery); args.putBoolean(ARG_NON_INTERACTIVE, nonInteractive); + args.putString(ARG_KEYSERVER_URL, keyserver); frag.setArguments(args); @@ -180,16 +207,23 @@ public class ImportKeysListFragment extends ListFragment implements setListAdapter(mAdapter); Bundle args = getArguments(); - Uri dataUri = args.containsKey(ARG_DATA_URI) ? args.getParcelable(ARG_DATA_URI) : null; - byte[] bytes = args.containsKey(ARG_BYTES) ? args.getByteArray(ARG_BYTES) : null; - String query = args.containsKey(ARG_SERVER_QUERY) ? args.getString(ARG_SERVER_QUERY) : null; - mNonInteractive = args.containsKey(ARG_NON_INTERACTIVE) ? args.getBoolean(ARG_NON_INTERACTIVE) : false; + Uri dataUri = args.getParcelable(ARG_DATA_URI); + byte[] bytes = args.getByteArray(ARG_BYTES); + String query = args.getString(ARG_SERVER_QUERY); + String keyserver = args.getString(ARG_KEYSERVER_URL); + mNonInteractive = args.getBoolean(ARG_NON_INTERACTIVE, false); if (dataUri != null || bytes != null) { mLoaderState = new BytesLoaderState(bytes, dataUri); } else if (query != null) { - Preferences prefs = Preferences.getPreferences(getActivity()); - mLoaderState = new CloudLoaderState(query, prefs.getCloudSearchPrefs()); + Preferences.CloudSearchPrefs cloudSearchPrefs; + if (keyserver != null) { + cloudSearchPrefs = Preferences.getPreferences(getActivity()).getCloudSearchPrefs(); + } else { + cloudSearchPrefs = new Preferences.CloudSearchPrefs(true, true, keyserver); + } + + mLoaderState = new CloudLoaderState(query, cloudSearchPrefs); } getListView().setOnTouchListener(new OnTouchListener() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 5447c5f96..139512ba9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -82,12 +82,12 @@ public class ImportKeysListLoader @Override protected void onStartLoading() { - forceLoad(); + super.forceLoad(); } @Override protected void onStopLoading() { - cancelLoad(); + super.cancelLoad(); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 8a7638054..303687315 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -193,6 +193,11 @@ public class Preferences { public final boolean searchKeybase; public final String keyserver; + /** + * @param searchKeyserver should passed keyserver be searched + * @param searchKeybase should keybase.io be searched + * @param keyserver the keyserver url authority to search on + */ public CloudSearchPrefs(boolean searchKeyserver, boolean searchKeybase, String keyserver) { this.searchKeyserver = searchKeyserver; this.searchKeybase = searchKeybase; diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index c1e3b51f9..d4c67aa23 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -404,6 +404,9 @@ "Scan QR Code" "Place your camera over the QR Code!" + + "No search parameter found. You may still attempt manually searching the keyserver." + "Details" ", with warnings" -- cgit v1.2.3 From 104fdcd6bf0442f44a5c591101d8a232bf6455ef Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 20 Apr 2015 17:27:55 -0400 Subject: Track state of PIN verification on smart card; only verify when needed. --- .../keychain/ui/base/BaseNfcActivity.java | 35 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index db7aba519..5990a8b5a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -57,6 +57,9 @@ public abstract class BaseNfcActivity extends BaseActivity { public static final int REQUEST_CODE_PASSPHRASE = 1; protected Passphrase mPin; + protected boolean mPw1ValidForMultipleSignatures; + protected boolean mPw1ValidatedForSignature; + protected boolean mPw1ValidatedForDecrypt; // Mode 82 does other things; consider renaming? private NfcAdapter mNfcAdapter; private IsoDep mIsoDep; @@ -201,6 +204,11 @@ public abstract class BaseNfcActivity extends BaseActivity { throw new IOException("Initialization failed!"); } + byte[] pwStatusBytes = nfcGetPwStatusBytes(); + mPw1ValidForMultipleSignatures = (pwStatusBytes[0] == 1); + mPw1ValidatedForSignature = false; + mPw1ValidatedForDecrypt = false; + onNfcPerform(); mIsoDep.close(); @@ -278,6 +286,15 @@ public abstract class BaseNfcActivity extends BaseActivity { return fptlv.mV; } + /** Return the PW Status Bytes from the card. This is a simple DO; no TLV decoding needed. + * + * @return Seven bytes in fixed format, plus 0x9000 status word at the end. + */ + public byte[] nfcGetPwStatusBytes() throws IOException { + String data = "00CA00C400"; + return mIsoDep.transceive(Hex.decode(data)); + } + /** Return the fingerprint from application specific data stored on tag, or * null if it doesn't exist. * @@ -316,7 +333,9 @@ public abstract class BaseNfcActivity extends BaseActivity { * @return a big integer representing the MPI for the given hash */ public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { - nfcVerifyPIN(0x81); // (Verify PW1 with mode 81 for signing) + if (!mPw1ValidatedForSignature) { + nfcVerifyPIN(0x81); // (Verify PW1 with mode 81 for signing) + } // dsi, including Lc String dsi; @@ -391,6 +410,10 @@ public abstract class BaseNfcActivity extends BaseActivity { Log.d(Constants.TAG, "final response:" + status); + if (!mPw1ValidForMultipleSignatures) { + mPw1ValidatedForSignature = false; + } + if ( ! "9000".equals(status)) { throw new IOException("Bad NFC response code: " + status); } @@ -410,7 +433,9 @@ public abstract class BaseNfcActivity extends BaseActivity { * @return the decoded session key */ public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { - nfcVerifyPIN(0x82); // (Verify PW1 with mode 82 for decryption) + if (!mPw1ValidatedForDecrypt) { + nfcVerifyPIN(0x82); // (Verify PW1 with mode 82 for decryption) + } String firstApdu = "102a8086fe"; String secondApdu = "002a808603"; @@ -458,6 +483,12 @@ public abstract class BaseNfcActivity extends BaseActivity { handlePinError(); throw new IOException("Bad PIN!"); } + + if (mode == 0x81) { + mPw1ValidatedForSignature = true; + } else if (mode == 0x82) { + mPw1ValidatedForDecrypt = true; + } } } -- cgit v1.2.3 From 9d56fc9768c10cc0e0331cda787abff64186371b Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Mon, 20 Apr 2015 17:38:36 -0400 Subject: Fix for initialization failure when card returns FCI in data field. --- .../java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 5990a8b5a..1d09b281f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -200,7 +200,7 @@ public abstract class BaseNfcActivity extends BaseActivity { + "06" // Lc (number of bytes) + "D27600012401" // Data (6 bytes) + "00"; // Le - if ( ! nfcCommunicate(opening).equals(accepted)) { // activate connection + if ( ! nfcCommunicate(opening).endsWith(accepted)) { // activate connection throw new IOException("Initialization failed!"); } -- cgit v1.2.3 From 5a4a8f2b6a0d5d8eb9b23269f72a369cab25f8ff Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Tue, 21 Apr 2015 23:16:33 +0530 Subject: added log to QR code scan/import fail --- .../keychain/ui/ImportKeysProxyActivity.java | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java index b9f1bf870..5c49de727 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -58,13 +58,12 @@ import java.util.Locale; public class ImportKeysProxyActivity extends FragmentActivity { public static final String ACTION_QR_CODE_API = OpenKeychainIntents.IMPORT_KEY_FROM_QR_CODE; + // implies activity returns scanned fingerprint as extra and does not import public static final String ACTION_SCAN_WITH_RESULT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_WITH_RESULT"; public static final String ACTION_SCAN_IMPORT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_IMPORT"; public static final String EXTRA_FINGERPRINT = "fingerprint"; - boolean returnResult; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -82,10 +81,8 @@ public class ImportKeysProxyActivity extends FragmentActivity { if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) { // Scanning a fingerprint directly with Barcode Scanner, thus we already have scanned - returnResult = false; processScannedContent(dataUri); } else if (ACTION_SCAN_IMPORT.equals(action) || ACTION_QR_CODE_API.equals(action)) { - returnResult = false; IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) .setPrompt(getString(R.string.import_qr_code_text)) @@ -93,7 +90,6 @@ public class ImportKeysProxyActivity extends FragmentActivity { integrator.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); integrator.initiateScan(); } else if (ACTION_SCAN_WITH_RESULT.equals(action)) { - returnResult = true; IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) .setPrompt(getString(R.string.import_qr_code_text)) @@ -103,7 +99,6 @@ public class ImportKeysProxyActivity extends FragmentActivity { } else if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { // Check to see if the Activity started due to an Android Beam if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - returnResult = false; handleActionNdefDiscovered(getIntent()); } else { Log.e(Constants.TAG, "Android Beam not supported by Android < 4.1"); @@ -148,6 +143,8 @@ public class ImportKeysProxyActivity extends FragmentActivity { private void processScannedContent(Uri uri) { + String action = getIntent().getAction(); + Log.d(Constants.TAG, "scanned: " + uri); String fingerprint = null; @@ -166,7 +163,7 @@ public class ImportKeysProxyActivity extends FragmentActivity { return; } - if (returnResult) { + if (ACTION_SCAN_WITH_RESULT.equals(action)) { Intent result = new Intent(); result.putExtra(EXTRA_FINGERPRINT, fingerprint); setResult(RESULT_OK, result); @@ -177,15 +174,17 @@ public class ImportKeysProxyActivity extends FragmentActivity { } public void returnResult(Intent data) { - if (returnResult) { - setResult(RESULT_OK, data); - finish(); - } else { + String action = getIntent().getAction(); + + if (ACTION_QR_CODE_API.equals(action)) { // display last log message but as Toast for calls from outside OpenKeychain OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); String str = getString(result.getLog().getLast().mType.getMsgId()); Toast.makeText(this, str, Toast.LENGTH_LONG).show(); finish(); + } else { + setResult(RESULT_OK, data); + finish(); } } @@ -209,7 +208,7 @@ public class ImportKeysProxyActivity extends FragmentActivity { } - private void startImportService (ArrayList keyRings) { + private void startImportService(ArrayList keyRings) { // Message is received after importing is done in KeychainIntentService ServiceProgressHandler serviceHandler = new ServiceProgressHandler( -- cgit v1.2.3 From 713f6ba6c79b703881e39d9d642b47f8140f8ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 21 Apr 2015 20:15:10 +0200 Subject: Simplify ImportKeysProxyActivity --- .../keychain/ui/ImportKeysProxyActivity.java | 41 +++++++--------------- 1 file changed, 12 insertions(+), 29 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java index 5c49de727..29f2511a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -82,14 +82,8 @@ public class ImportKeysProxyActivity extends FragmentActivity { // Scanning a fingerprint directly with Barcode Scanner, thus we already have scanned processScannedContent(dataUri); - } else if (ACTION_SCAN_IMPORT.equals(action) || ACTION_QR_CODE_API.equals(action)) { - IntentIntegrator integrator = new IntentIntegrator(this); - integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) - .setPrompt(getString(R.string.import_qr_code_text)) - .setResultDisplayDuration(0); - integrator.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - integrator.initiateScan(); - } else if (ACTION_SCAN_WITH_RESULT.equals(action)) { + } else if (ACTION_SCAN_WITH_RESULT.equals(action) + || ACTION_SCAN_IMPORT.equals(action) || ACTION_QR_CODE_API.equals(action)) { IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) .setPrompt(getString(R.string.import_qr_code_text)) @@ -142,34 +136,28 @@ public class ImportKeysProxyActivity extends FragmentActivity { } private void processScannedContent(Uri uri) { - String action = getIntent().getAction(); Log.d(Constants.TAG, "scanned: " + uri); - String fingerprint = null; - // example: openpgp4fpr:73EE2314F65FA92EC2390D3A718C070100012282 if (uri != null && uri.getScheme() != null && uri.getScheme().toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) { - fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); - } + String fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); - if (fingerprint == null) { + if (ACTION_SCAN_WITH_RESULT.equals(action)) { + Intent result = new Intent(); + result.putExtra(EXTRA_FINGERPRINT, fingerprint); + setResult(RESULT_OK, result); + finish(); + } else { + importKeys(fingerprint); + } + } else { SingletonResult result = new SingletonResult( SingletonResult.RESULT_ERROR, OperationResult.LogType.MSG_WRONG_QR_CODE); Intent intent = new Intent(); intent.putExtra(SingletonResult.EXTRA_RESULT, result); returnResult(intent); - return; - } - - if (ACTION_SCAN_WITH_RESULT.equals(action)) { - Intent result = new Intent(); - result.putExtra(EXTRA_FINGERPRINT, fingerprint); - setResult(RESULT_OK, result); - finish(); - } else { - importKeys(fingerprint); } } @@ -189,23 +177,19 @@ public class ImportKeysProxyActivity extends FragmentActivity { } public void importKeys(byte[] keyringData) { - ParcelableKeyRing keyEntry = new ParcelableKeyRing(keyringData); ArrayList selectedEntries = new ArrayList<>(); selectedEntries.add(keyEntry); startImportService(selectedEntries); - } public void importKeys(String fingerprint) { - ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null); ArrayList selectedEntries = new ArrayList<>(); selectedEntries.add(keyEntry); startImportService(selectedEntries); - } private void startImportService(ArrayList keyRings) { @@ -281,7 +265,6 @@ public class ImportKeysProxyActivity extends FragmentActivity { // start service with intent startService(intent); - } /** -- cgit v1.2.3 From 09cb00a87c78256f7d085dfde06b61e89ff28a25 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Wed, 22 Apr 2015 03:32:59 +0530 Subject: corrected possible null pointer --- .../java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 81ff87216..bf7e41045 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -217,7 +217,7 @@ public class ImportKeysListFragment extends ListFragment implements mLoaderState = new BytesLoaderState(bytes, dataUri); } else if (query != null) { Preferences.CloudSearchPrefs cloudSearchPrefs; - if (keyserver != null) { + if (keyserver == null) { cloudSearchPrefs = Preferences.getPreferences(getActivity()).getCloudSearchPrefs(); } else { cloudSearchPrefs = new Preferences.CloudSearchPrefs(true, true, keyserver); -- cgit v1.2.3 From 2571d25058706ae2725e0a70db4fa1c7eacfc153 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Wed, 22 Apr 2015 06:15:14 +0530 Subject: keyserver verification on addition --- .../keychain/ui/SettingsKeyServerActivity.java | 60 +++- .../ui/dialog/AddKeyserverDialogFragment.java | 320 +++++++++++++++++++++ .../src/main/res/layout/add_keyserver_dialog.xml | 29 ++ OpenKeychain/src/main/res/values/strings.xml | 12 + 4 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java create mode 100644 OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java index 9f2e46b38..8f025c769 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java @@ -20,6 +20,9 @@ package org.sufficientlysecure.keychain.ui; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -28,6 +31,8 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.base.BaseActivity; +import org.sufficientlysecure.keychain.ui.dialog.AddKeyserverDialogFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.Editor; import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; @@ -95,7 +100,7 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi Intent intent = getIntent(); String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS); makeServerList(servers); - } + } @Override protected void initLayout() { @@ -124,10 +129,63 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi } + // button to add keyserver clicked public void onClick(View v) { + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + Bundle data = message.getData(); + switch (message.what) { + case AddKeyserverDialogFragment.MESSAGE_OKAY: { + boolean verified = data.getBoolean(AddKeyserverDialogFragment.MESSAGE_VERIFIED); + if (verified) { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_verified, Notify.Style.OK).show(); + } else { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_without_verification, + Notify.Style.WARN).show(); + } + String keyserver = data.getString(AddKeyserverDialogFragment.MESSAGE_KEYSERVER); + addKeyserver(keyserver); + break; + } + case AddKeyserverDialogFragment.MESSAGE_VERIFICATION_FAILED: { + AddKeyserverDialogFragment.FailureReason failureReason = + (AddKeyserverDialogFragment.FailureReason) data.getSerializable( + AddKeyserverDialogFragment.MESSAGE_FAILURE_REASON); + switch (failureReason) { + case CONNECTION_FAILED: { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_connection_failed, + Notify.Style.ERROR).show(); + break; + } + case INVALID_URL: { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_invalid_url, + Notify.Style.ERROR).show(); + break; + } + } + break; + } + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + AddKeyserverDialogFragment dialogFragment = AddKeyserverDialogFragment + .newInstance(messenger, R.string.add_keyserver_dialog_title); + dialogFragment.show(getSupportFragmentManager(), "addKeyserverDialog"); + } + + public void addKeyserver(String keyserverUrl) { KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor, mEditors, false); view.setEditorListener(this); + view.setValue(keyserverUrl); mEditors.addView(view); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java new file mode 100644 index 000000000..cbef5950f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v4.app.DialogFragment; +import android.test.suitebuilder.TestSuiteBuilder; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.TlsHelper; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +import javax.net.ssl.HttpsURLConnection; + +public class AddKeyserverDialogFragment extends DialogFragment implements OnEditorActionListener { + private static final String ARG_MESSENGER = "messenger"; + private static final String ARG_TITLE = "title"; + + public static final int MESSAGE_OKAY = 1; + public static final int MESSAGE_VERIFICATION_FAILED = 2; + + public static final String MESSAGE_KEYSERVER = "new_keyserver"; + public static final String MESSAGE_VERIFIED = "verified"; + public static final String MESSAGE_FAILURE_REASON = "failure_reason"; + + private Messenger mMessenger; + private EditText mKeyserverEditText; + private CheckBox mVerifyKeyserverCheckBox; + + public static enum FailureReason { + INVALID_URL, + CONNECTION_FAILED + } + + ; + + /** + * Creates new instance of this dialog fragment + * + * @param title title of dialog + * @param messenger to communicate back after setting the passphrase + * @return + */ + public static AddKeyserverDialogFragment newInstance(Messenger messenger, int title) { + AddKeyserverDialogFragment frag = new AddKeyserverDialogFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_TITLE, title); + args.putParcelable(ARG_MESSENGER, messenger); + + frag.setArguments(args); + + return frag; + } + + /** + * Creates dialog + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Activity activity = getActivity(); + + int title = getArguments().getInt(ARG_TITLE); + mMessenger = getArguments().getParcelable(ARG_MESSENGER); + + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); + + alert.setTitle(title); + + LayoutInflater inflater = activity.getLayoutInflater(); + View view = inflater.inflate(R.layout.add_keyserver_dialog, null); + alert.setView(view); + + mKeyserverEditText = (EditText) view.findViewById(R.id.keyserver_url_edit_text); + mVerifyKeyserverCheckBox = (CheckBox) view.findViewById(R.id.verify_keyserver_checkbox); + + // we don't want dialog to be dismissed on click, thereby requiring the hack seen below + // and in onStart + alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // we need to have an empty listener to prevent errors on some devices as mentioned + // at http://stackoverflow.com/q/13746412/3000919 + // actual listener set in onStart + } + }); + + alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + dismiss(); + } + }); + + // Hack to open keyboard. + // This is the only method that I found to work across all Android versions + // http://turbomanage.wordpress.com/2012/05/02/show-soft-keyboard-automatically-when-edittext-receives-focus/ + // Notes: * onCreateView can't be used because we want to add buttons to the dialog + // * opening in onActivityCreated does not work on Android 4.4 + mKeyserverEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + mKeyserverEditText.post(new Runnable() { + @Override + public void run() { + InputMethodManager imm = (InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(mKeyserverEditText, InputMethodManager.SHOW_IMPLICIT); + } + }); + } + }); + mKeyserverEditText.requestFocus(); + + mKeyserverEditText.setImeActionLabel(getString(android.R.string.ok), + EditorInfo.IME_ACTION_DONE); + mKeyserverEditText.setOnEditorActionListener(this); + + return alert.show(); + } + + @Override + public void onStart() { + super.onStart(); + AlertDialog addKeyserverDialog = (AlertDialog) getDialog(); + if (addKeyserverDialog != null) { + Button positiveButton = addKeyserverDialog.getButton(Dialog.BUTTON_POSITIVE); + positiveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String keyserverUrl = mKeyserverEditText.getText().toString(); + if (mVerifyKeyserverCheckBox.isChecked()) { + verifyConnection(keyserverUrl); + } else { + dismiss(); + // return unverified keyserver back to activity + addKeyserver(keyserverUrl, false); + } + } + }); + } + } + + public void addKeyserver(String keyserver, boolean verified) { + dismiss(); + Bundle data = new Bundle(); + data.putString(MESSAGE_KEYSERVER, keyserver); + data.putBoolean(MESSAGE_VERIFIED, verified); + + sendMessageToHandler(MESSAGE_OKAY, data); + } + + public void verificationFailed(FailureReason reason) { + Bundle data = new Bundle(); + data.putSerializable(MESSAGE_FAILURE_REASON, reason); + + sendMessageToHandler(MESSAGE_VERIFICATION_FAILED, data); + } + + public void verifyConnection(String keyserver) { + + new AsyncTask() { + ProgressDialog mProgressDialog; + String mKeyserver; + + @Override + protected void onPreExecute() { + mProgressDialog = new ProgressDialog(getActivity()); + mProgressDialog.setMessage(getString(R.string.progress_verifying_keyserver_url)); + mProgressDialog.setCancelable(false); + mProgressDialog.show(); + } + + @Override + protected FailureReason doInBackground(String... keyservers) { + mKeyserver = keyservers[0]; + FailureReason reason = null; + try { + // replace hkps/hkp scheme and reconstruct Uri + Uri keyserverUri = Uri.parse(mKeyserver); + String scheme = keyserverUri.getScheme(); + String schemeSpecificPart = keyserverUri.getSchemeSpecificPart(); + String fragment = keyserverUri.getFragment(); + if (scheme == null) throw new MalformedURLException(); + if (scheme.equalsIgnoreCase("hkps")) scheme = "https"; + else if (scheme.equalsIgnoreCase("hkp")) scheme = "http"; + URI newKeyserver = new URI(scheme, schemeSpecificPart, fragment); + + Log.d("Converted URL", newKeyserver.toString()); + TlsHelper.openConnection(newKeyserver.toURL()).getInputStream(); + } catch (TlsHelper.TlsHelperException e) { + reason = FailureReason.CONNECTION_FAILED; + } catch (MalformedURLException e) { + Log.w(Constants.TAG, "Invalid keyserver URL entered by user."); + reason = FailureReason.INVALID_URL; + } catch (URISyntaxException e) { + Log.w(Constants.TAG, "Invalid keyserver URL entered by user."); + reason = FailureReason.INVALID_URL; + } catch (IOException e) { + Log.w(Constants.TAG, "Could not connect to entered keyserver url"); + reason = FailureReason.CONNECTION_FAILED; + } + return reason; + } + + @Override + protected void onPostExecute(FailureReason failureReason) { + mProgressDialog.dismiss(); + if (failureReason == null) { + addKeyserver(mKeyserver, true); + } else { + verificationFailed(failureReason); + } + } + }.execute(keyserver); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + + // hide keyboard on dismiss + hideKeyboard(); + } + + private void hideKeyboard() { + if (getActivity() == null) { + return; + } + InputMethodManager inputManager = (InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE); + + //check if no view has focus: + View v = getActivity().getCurrentFocus(); + if (v == null) + return; + + inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0); + } + + /** + * Associate the "done" button on the soft keyboard with the okay button in the view + */ + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (EditorInfo.IME_ACTION_DONE == actionId) { + AlertDialog dialog = ((AlertDialog) getDialog()); + Button bt = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + + bt.performClick(); + return true; + } + return false; + } + + /** + * Send message back to handler which is initialized in a activity + * + * @param what Message integer you want to send + */ + private void sendMessageToHandler(Integer what, Bundle data) { + Message msg = Message.obtain(); + msg.what = what; + if (data != null) { + msg.setData(data); + } + + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); + } catch (NullPointerException e) { + Log.w(Constants.TAG, "Messenger is null!", e); + } + } +} diff --git a/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml new file mode 100644 index 000000000..78e9247ea --- /dev/null +++ b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index d4c67aa23..fa8bd16b9 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -86,6 +86,7 @@ "Encrypt text" "Add additional email address" "Unlock" + "Add" "Settings" @@ -152,6 +153,8 @@ "Enable compression" "Encrypt filenames" "Hide recipients" + "Verify Keyserver" + "Enter Keyserver URL" "Search Keyserver" "Search HKP keyserver" @@ -353,6 +356,8 @@ "consolidate: saving to cache…" "consolidate: reimporting…" + "verifying keyserver…" + "Search via Name, Email…" @@ -645,6 +650,13 @@ "<none>" + + "Add Keyserver" + "Keyserver verified!" + "Keyserver added without verification." + "Invalid URL!" + "Failed to connect to keyserver. Please check the URL and your internet connection." + "Keys" "Encrypt/Decrypt" -- cgit v1.2.3 From aecebd2ac012804477ab3ec59ca6cf0417a56c5f Mon Sep 17 00:00:00 2001 From: Manoj Khanna Date: Wed, 22 Apr 2015 18:30:35 +0530 Subject: Fixed Snackbar behind layout Surrounded string with quotes --- .../keychain/ui/EncryptFilesFragment.java | 14 +++++------ .../keychain/ui/EncryptTextFragment.java | 12 +++++----- .../src/main/res/layout/encrypt_files_fragment.xml | 4 ++-- .../src/main/res/layout/encrypt_text_fragment.xml | 27 +++++++++++----------- OpenKeychain/src/main/res/values/strings.xml | 1 + 5 files changed, 29 insertions(+), 29 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index ccb4a6355..458810541 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -202,7 +202,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } catch (IOException e) { Notify.create(getActivity(), getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)), - Notify.Style.ERROR).show(); + Notify.Style.ERROR).show(this); return; } mSelectedFiles.requestFocus(); @@ -230,7 +230,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { private void encryptClicked(boolean share) { if (mFilesModels.isEmpty()) { Notify.create(getActivity(), R.string.error_no_file_selected, - Notify.Style.ERROR).show(); + Notify.Style.ERROR).show(this); return; } if (share) { @@ -247,7 +247,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } else { if (mFilesModels.size() > 1) { Notify.create(getActivity(), R.string.error_multi_not_supported, - Notify.Style.ERROR).show(); + Notify.Style.ERROR).show(this); return; } showOutputFileDialog(); @@ -330,7 +330,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (mFilesModels.isEmpty()) { Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR) - .show(); + .show(this); return false; } else if (mFilesModels.size() > 1 && !mShareAfterEncrypt) { Log.e(Constants.TAG, "Aborting: mInputUris.size() > 1 && !mShareAfterEncrypt"); @@ -347,12 +347,12 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (mPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(); + .show(this); return false; } if (mPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(); + .show(this); return false; } @@ -365,7 +365,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { // Files must be encrypted, only text can be signed-only right now if (!gotEncryptionKeys) { Notify.create(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR) - .show(); + .show(this); return false; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index b37a2ca79..3f9147cc4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -288,9 +288,9 @@ public class EncryptTextFragment extends CryptoOperationFragment { } protected boolean inputIsValid() { - if (mMessage == null) { - Notify.create(getActivity(), R.string.error_message, Notify.Style.ERROR) - .show(); + if (mMessage == null || mMessage.isEmpty()) { + Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR) + .show(this); return false; } @@ -299,12 +299,12 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (mSymmetricPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(); + .show(this); return false; } if (mSymmetricPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(); + .show(this); return false; } @@ -316,7 +316,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (!gotEncryptionKeys && mSigningKeyId == 0) { Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR) - .show(); + .show(this); return false; } } diff --git a/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml index b75ec5022..8fd2c79fc 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml @@ -1,5 +1,5 @@ - @@ -12,4 +12,4 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - \ No newline at end of file + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml index 3c21291cd..7645918f4 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml @@ -1,25 +1,24 @@ - + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:fillViewport="true"> + android:hint="@string/encrypt_content_edit_text_hint" /> - - + + + diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index fa8bd16b9..df88336a1 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1238,6 +1238,7 @@ "Swipe down to update from keyserver" "Select at least one file to encrypt!" "Saving of multiple files not supported. This is a limitation on current Android." + "Type some text to encrypt!" "Key:" "To start a key exchange, choose the number of participants on the right side, then hit the “Start exchange” button.\n\nYou will be asked two more questions to make sure only the right participants are in the exchange and their fingerprints are correct." "Start exchange" -- cgit v1.2.3 From a4e871030d80a14fd0bc34b6ceb2e2f2d00bbabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 22 Apr 2015 19:00:18 +0200 Subject: Update changelog --- OpenKeychain/src/main/res/raw/help_changelog.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/res/raw/help_changelog.md b/OpenKeychain/src/main/res/raw/help_changelog.md index 104454f39..98639de71 100644 --- a/OpenKeychain/src/main/res/raw/help_changelog.md +++ b/OpenKeychain/src/main/res/raw/help_changelog.md @@ -2,8 +2,9 @@ ## 3.2beta2 + * First version with full YubiKey support available from the user interface: Edit keys, bind YubiKey to keys,... * Material design - * Integration of QR Scanner (New permissions required) + * Integration of QR Code Scanning (New permissions required) * Improved key creation wizard * Fix missing contacts after sync * Requires Android 4 @@ -13,6 +14,7 @@ * Fix: Some valid keys were shown revoked or expired * Don't accept signatures by expired or revoked subkeys * Keybase.io support in advanced view + * Method to update all keys at once ## 3.1.2 @@ -35,7 +37,7 @@ * Redesigned decrypt screen * New icon usage and colors * Fix import of secret keys from Symantec Encryption Desktop - * Subkey IDs on YubiKeys are now checked correctly + * Experimental YubiKey support: Subkey IDs are now checked correctly ## 3.0.1 @@ -46,7 +48,6 @@ ## 3.0 - * Full support for YubiKey signature generation and decryption! * Propose installable compatible apps in apps list * New design for decryption screens * Many fixes for key import, also fixes stripped keys @@ -55,12 +56,13 @@ * Fixing user id revocation certificates * New cloud search (searches over traditional keyservers and keybase.io) * Support for stripping keys inside OpenKeychain + * Experimental YubiKey support: Support for signature generation and decryption ## 2.9.2 * Fix keys broken in 2.9.1 - * YubiKey decryption now working via API + * Experimental YubiKey support: Decryption now working via API ## 2.9.1 @@ -69,7 +71,7 @@ * Fix key flags handling (now supporting Mailvelope 0.7 keys) * Improved passphrase handling * Key sharing via SafeSlinger - * YubiKey: preference to allow other PINs, currently only signing via the OpenPGP API works, not inside of OpenKeychain + * Experimental YubiKey support: Preference to allow other PINs, currently only signing via the OpenPGP API works, not inside of OpenKeychain * Fix usage of stripped keys * SHA256 as default for compatibility * Intent API has changed, see https://github.com/open-keychain/open-keychain/wiki/Intent-API @@ -80,7 +82,7 @@ * Fixing crashes introduced in v2.8 * Experimental ECC support - * Experimental YubiKey support (signing-only with imported keys) + * Experimental YubiKey support: Only signing with imported keys ## 2.8 -- cgit v1.2.3 From 3ee2c6fc6a2a5e18e333bb82f16d0efe365df2b8 Mon Sep 17 00:00:00 2001 From: vectorijk Date: Fri, 24 Apr 2015 00:00:58 -0700 Subject: Introduce and Switch to mikepenz/MaterialDrawer --- OpenKeychain/build.gradle | 10 ++ .../keychain/ui/MainActivity.java | 143 +++++++++++++++++---- OpenKeychain/src/main/res/layout/main_activity.xml | 17 +++ .../src/main/res/layout/main_drawer_header.xml | 9 ++ 4 files changed, 154 insertions(+), 25 deletions(-) create mode 100644 OpenKeychain/src/main/res/layout/main_activity.xml create mode 100644 OpenKeychain/src/main/res/layout/main_drawer_header.xml (limited to 'OpenKeychain') diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index 0f9446713..6341766f9 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -23,6 +23,11 @@ dependencies { compile "com.splitwise:tokenautocomplete:1.3.3@aar" compile 'se.emilsjolander:stickylistheaders:2.6.0' compile 'org.sufficientlysecure:html-textview:1.1' + compile 'com.mikepenz.materialdrawer:library:2.7.9@aar' + compile 'com.mikepenz.iconics:library:0.9.1@aar' + compile 'com.mikepenz.iconics:octicons-typeface:2.2.0@aar' + compile 'com.mikepenz.iconics:meteocons-typeface:1.1.1@aar' + compile 'com.mikepenz.iconics:community-material-typeface:1.0.0@aar' // libs as submodules compile project(':extern:openpgp-api-lib') @@ -56,6 +61,11 @@ dependencyVerification { 'com.splitwise:tokenautocomplete:20bee71cc59b3828eb000b684d46ddf738efd56b8fee453a509cd16fda42c8cb', 'se.emilsjolander:stickylistheaders:8c05981ec5725be33f7cee5e68c13f3db49cd5c75f1aaeb04024920b1ef96ad4', 'org.sufficientlysecure:html-textview:ca24b1522be88378634093815ce9ff1b4920c72e7513a045a7846e14069ef988', + 'com.mikepenz.materialdrawer:library:3ef80c6e1ca1b29cfcbb27fa7927c02b2246e068c17fe52283703c4897449923', + 'com.mikepenz.iconics:library:4698a36ee4c2af765d0a85779c61474d755b90d66a59020105b6760a8a909e9e', + 'com.mikepenz.iconics:octicons-typeface:67ed7d456a9ce5f5307b85f955797bfb3dd674e2f6defb31c6b8bbe2ede290be', + 'com.mikepenz.iconics:meteocons-typeface:39a8a9e70cd8287cdb119af57a672a41dd09240dba6697f5a0dbda1ccc33298b', + 'com.mikepenz.iconics:community-material-typeface:f1c5afee5f0f10d66beb3ed0df977246a02a9c46de4e05d7c0264bcde53b6b7f', // 'OpenKeychain.extern:openpgp-api-lib:f05a9215cdad3a6597e4c5ece6fcec92b178d218195a3e88d2c0937c48dd9580', // 'OpenKeychain.extern:openkeychain-api-lib:50f6ebb5452d3fdc7be137ccf857a0ff44d55539fcb7b91baef495766ed7f429', // 'com.madgag.spongycastle:core:df8fcc028a95ac5ffab3b78c9163f5cfa672e41cd50128ca55d458b6cfbacf4b', diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 5fa3edba4..045d1e658 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2012-2014 Dominik Schürmann * Copyright (C) 2014 Vincent Breitmoser + * Copyright (C) 2015 Kai Jiang * * 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 @@ -20,6 +21,20 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Toast; + +import com.mikepenz.community_material_typeface_library.CommunityMaterial; +import com.mikepenz.google_material_typeface_library.GoogleMaterial; +import com.mikepenz.iconics.typeface.FontAwesome; +import com.mikepenz.materialdrawer.Drawer; +import com.mikepenz.materialdrawer.model.DividerDrawerItem; +import com.mikepenz.materialdrawer.model.SectionDrawerItem; +import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; +import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; @@ -29,27 +44,78 @@ import org.sufficientlysecure.keychain.util.FabContainer; import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; -public class MainActivity extends MaterialNavigationDrawer implements FabContainer { - - @Override - public void init(Bundle savedInstanceState) { - // don't open drawer on first run - disableLearningPattern(); +public class MainActivity extends ActionBarActivity implements FabContainer { -// addMultiPaneSupport(); + public Drawer.Result result; - // set the header image - // create and set the header - setDrawerHeaderImage(R.drawable.drawer_header); +// public Drawer.Result result; + @Override + public void onCreate(Bundle savedInstanceState) { +// // don't open drawer on first run +// disableLearningPattern(); +// +//// addMultiPaneSupport(); +// +// // set the header image +// // create and set the header +// setDrawerHeaderImage(R.drawable.drawer_header); +// +// // create sections +// addSection(newSection(getString(R.string.nav_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); +// addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); +// addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); +// +// // create bottom section +// addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); +// addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); + super.onCreate(savedInstanceState); + setContentView(R.layout.main_activity); - // create sections - addSection(newSection(getString(R.string.nav_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); - addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); - addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); + final Toolbar toolbar = (Toolbar) findViewById(R.id.activity_main_toolbar); + toolbar.setTitle(R.string.app_name); + setSupportActionBar(toolbar); - // create bottom section - addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); - addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); + result = new Drawer() + .withActivity(this) + .withHeader(R.layout.main_drawer_header) + .withToolbar(toolbar) + .addDrawerItems( + new PrimaryDrawerItem().withName(R.string.nav_keys).withIcon(CommunityMaterial.Icon.cmd_key).withIdentifier(1).withCheckable(false), + new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock).withIdentifier(2).withCheckable(false), + new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps).withIdentifier(3).withCheckable(false), + new DividerDrawerItem(), + new PrimaryDrawerItem().withName(R.string.menu_preferences).withIcon(GoogleMaterial.Icon.gmd_settings).withIdentifier(4).withCheckable(false), + new PrimaryDrawerItem().withName(R.string.menu_help).withIcon(CommunityMaterial.Icon.cmd_help_circle).withIdentifier(5).withCheckable(false) + ) + .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id, IDrawerItem drawerItem) { + if (drawerItem != null) { + Intent intent = null; + switch(drawerItem.getIdentifier()) { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + intent = new Intent(MainActivity.this, SettingsActivity.class); + break; + case 5: + intent = new Intent(MainActivity.this, HelpActivity.class); + break; + } + if (intent != null) { + MainActivity.this.startActivity(intent); + } + } + Toast.makeText(MainActivity.this, Integer.toString(drawerItem.getIdentifier()), Toast.LENGTH_SHORT).show(); + } + }) + .withSelectedItem(-1) + .withSavedInstance(savedInstanceState) + .build(); // if this is the first time show first time activity Preferences prefs = Preferences.getPreferences(this); @@ -69,20 +135,47 @@ public class MainActivity extends MaterialNavigationDrawer implements FabContain } } +// private void onPreferenceSelected() { +// Intent intent = new Intent(this, SettingsActivity.class); +// startActivity(intent); +// } +// +// private void onHelpSelected() { +// Intent intent = new Intent(this, HelpActivity.class); +// startActivity(intent); +// } + @Override - public void fabMoveUp(int height) { - Object fragment = getCurrentSection().getTargetFragment(); - if (fragment instanceof FabContainer) { - ((FabContainer) fragment).fabMoveUp(height); + protected void onSaveInstanceState(Bundle outState) { + //add the values which need to be saved from the drawer to the bundle + outState = result.saveInstanceState(outState); + super.onSaveInstanceState(outState); + } + + @Override + public void onBackPressed(){ + //handle the back press :D close the drawer first and if the drawer is closed close the activity + if (result != null && result.isDrawerOpen()) { + result.closeDrawer(); + } else { + super.onBackPressed(); } } + @Override + public void fabMoveUp(int height) { +// Object fragment = getCurrentSection().getTargetFragment(); +// if (fragment instanceof FabContainer) { +// ((FabContainer) fragment).fabMoveUp(height); +// } + } + @Override public void fabRestorePosition() { - Object fragment = getCurrentSection().getTargetFragment(); - if (fragment instanceof FabContainer) { - ((FabContainer) fragment).fabRestorePosition(); - } +// Object fragment = getCurrentSection().getTargetFragment(); +// if (fragment instanceof FabContainer) { +// ((FabContainer) fragment).fabRestorePosition(); +// } } } diff --git a/OpenKeychain/src/main/res/layout/main_activity.xml b/OpenKeychain/src/main/res/layout/main_activity.xml new file mode 100644 index 000000000..a85c8047e --- /dev/null +++ b/OpenKeychain/src/main/res/layout/main_activity.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/main_drawer_header.xml b/OpenKeychain/src/main/res/layout/main_drawer_header.xml new file mode 100644 index 000000000..bac52efb3 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/main_drawer_header.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file -- cgit v1.2.3 From b323fc29c29ec2a7cba87ed19c7809b843a1fd60 Mon Sep 17 00:00:00 2001 From: vectorijk Date: Fri, 24 Apr 2015 03:21:54 -0700 Subject: Fix #1197 Switch to MaterialDrawer library --- .../keychain/ui/MainActivity.java | 129 ++++++++++++++------- OpenKeychain/src/main/res/layout/main_activity.xml | 6 +- 2 files changed, 89 insertions(+), 46 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 045d1e658..fa4f07d88 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -21,56 +21,48 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.AdapterView; -import android.widget.Toast; import com.mikepenz.community_material_typeface_library.CommunityMaterial; import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.iconics.typeface.FontAwesome; import com.mikepenz.materialdrawer.Drawer; -import com.mikepenz.materialdrawer.model.DividerDrawerItem; -import com.mikepenz.materialdrawer.model.SectionDrawerItem; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.FabContainer; - -import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; +import org.sufficientlysecure.keychain.util.Preferences; public class MainActivity extends ActionBarActivity implements FabContainer { public Drawer.Result result; -// public Drawer.Result result; + private KeyListFragment mKeyListFragment ; + private AppsListFragment mAppsListFragment; + private EncryptDecryptOverviewFragment mEncryptDecryptOverviewFragment; + private Fragment lastUsedFragment; + @Override public void onCreate(Bundle savedInstanceState) { -// // don't open drawer on first run -// disableLearningPattern(); -// -//// addMultiPaneSupport(); -// -// // set the header image -// // create and set the header -// setDrawerHeaderImage(R.drawable.drawer_header); -// -// // create sections -// addSection(newSection(getString(R.string.nav_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); -// addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); -// addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); -// -// // create bottom section -// addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); -// addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); + //initialize FragmentLayout with KeyListFragment at first + Fragment mainFragment = new KeyListFragment(); + FragmentManager fm = getSupportFragmentManager(); + FragmentTransaction transaction = fm.beginTransaction(); + transaction.replace(R.id.main_fragment_container, mainFragment); + transaction.commit(); + final Toolbar toolbar = (Toolbar) findViewById(R.id.activity_main_toolbar); toolbar.setTitle(R.string.app_name); setSupportActionBar(toolbar); @@ -82,8 +74,10 @@ public class MainActivity extends ActionBarActivity implements FabContainer { .addDrawerItems( new PrimaryDrawerItem().withName(R.string.nav_keys).withIcon(CommunityMaterial.Icon.cmd_key).withIdentifier(1).withCheckable(false), new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock).withIdentifier(2).withCheckable(false), - new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps).withIdentifier(3).withCheckable(false), - new DividerDrawerItem(), + new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps).withIdentifier(3).withCheckable(false) + ) + .addStickyDrawerItems( + // display and stick on bottom of drawer new PrimaryDrawerItem().withName(R.string.menu_preferences).withIcon(GoogleMaterial.Icon.gmd_settings).withIdentifier(4).withCheckable(false), new PrimaryDrawerItem().withName(R.string.menu_help).withIcon(CommunityMaterial.Icon.cmd_help_circle).withIdentifier(5).withCheckable(false) ) @@ -94,10 +88,13 @@ public class MainActivity extends ActionBarActivity implements FabContainer { Intent intent = null; switch(drawerItem.getIdentifier()) { case 1: + onKeysSelected(); break; case 2: + onEnDecryptSelected(); break; case 3: + onAppsSelected(); break; case 4: intent = new Intent(MainActivity.this, SettingsActivity.class); @@ -110,7 +107,6 @@ public class MainActivity extends ActionBarActivity implements FabContainer { MainActivity.this.startActivity(intent); } } - Toast.makeText(MainActivity.this, Integer.toString(drawerItem.getIdentifier()), Toast.LENGTH_SHORT).show(); } }) .withSelectedItem(-1) @@ -135,15 +131,58 @@ public class MainActivity extends ActionBarActivity implements FabContainer { } } -// private void onPreferenceSelected() { -// Intent intent = new Intent(this, SettingsActivity.class); -// startActivity(intent); -// } -// -// private void onHelpSelected() { -// Intent intent = new Intent(this, HelpActivity.class); -// startActivity(intent); -// } + private void clearFragments() { + mKeyListFragment = null; + mAppsListFragment = null; + mEncryptDecryptOverviewFragment = null; + + getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + + private void setFragment(Fragment fragment) { + setFragment(fragment, true); + } + + private void setFragment(Fragment fragment, boolean addToBackStack) { + this.lastUsedFragment = fragment; + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.replace(R.id.main_fragment_container, fragment); + if (addToBackStack) { + ft.addToBackStack(null); + } + ft.commit(); + } + + private boolean onKeysSelected() { + clearFragments(); + + if (mKeyListFragment == null) { + mKeyListFragment = new KeyListFragment(); + } + + setFragment(mKeyListFragment, false); + return true; + } + + private boolean onEnDecryptSelected() { + clearFragments(); + if (mEncryptDecryptOverviewFragment == null) { + mEncryptDecryptOverviewFragment = new EncryptDecryptOverviewFragment(); + } + + setFragment(mEncryptDecryptOverviewFragment); + return true; + } + + private boolean onAppsSelected() { + clearFragments(); + if (mAppsListFragment == null) { + mAppsListFragment = new AppsListFragment(); + } + + setFragment(mAppsListFragment); + return true; + } @Override protected void onSaveInstanceState(Bundle outState) { @@ -164,18 +203,20 @@ public class MainActivity extends ActionBarActivity implements FabContainer { @Override public void fabMoveUp(int height) { -// Object fragment = getCurrentSection().getTargetFragment(); -// if (fragment instanceof FabContainer) { -// ((FabContainer) fragment).fabMoveUp(height); -// } + Object fragment = getSupportFragmentManager() + .findFragmentById(R.id.main_fragment_container); + if (fragment instanceof FabContainer) { + ((FabContainer) fragment).fabMoveUp(height); + } } @Override public void fabRestorePosition() { -// Object fragment = getCurrentSection().getTargetFragment(); -// if (fragment instanceof FabContainer) { -// ((FabContainer) fragment).fabRestorePosition(); -// } + Object fragment = getSupportFragmentManager() + .findFragmentById(R.id.main_fragment_container); + if (fragment instanceof FabContainer) { + ((FabContainer) fragment).fabRestorePosition(); + } } } diff --git a/OpenKeychain/src/main/res/layout/main_activity.xml b/OpenKeychain/src/main/res/layout/main_activity.xml index a85c8047e..4a07053ea 100644 --- a/OpenKeychain/src/main/res/layout/main_activity.xml +++ b/OpenKeychain/src/main/res/layout/main_activity.xml @@ -7,11 +7,13 @@ android:id="@+id/activity_main_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:elevation="4dp" android:background="?attr/colorPrimary"/> - + \ No newline at end of file -- cgit v1.2.3 From 96853a15ee535860fd789bc5be4979f2205e959c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 24 Apr 2015 19:00:33 +0200 Subject: revamp decrypt ui --- .../keychain/ui/DecryptFilesFragment.java | 6 +- .../keychain/ui/DecryptFragment.java | 416 +++++++++++++++------ .../keychain/ui/DecryptTextFragment.java | 74 ++-- .../src/main/res/layout/decrypt_result_include.xml | 44 +-- .../src/main/res/layout/decrypt_text_fragment.xml | 49 --- OpenKeychain/src/main/res/menu/decrypt_menu.xml | 17 + OpenKeychain/src/main/res/values/strings.xml | 15 +- 7 files changed, 391 insertions(+), 230 deletions(-) create mode 100644 OpenKeychain/src/main/res/menu/decrypt_menu.xml (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index 766e65e8b..6c1902af1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -240,7 +240,7 @@ public class DecryptFilesFragment extends DecryptFragment { } case KeychainIntentService.ACTION_DECRYPT_VERIFY: { // display signature result in activity - onResult(pgpResult); + loadVerifyResult(pgpResult); if (mDeleteAfter.isChecked()) { // Create and show dialog to delete original file @@ -308,4 +308,8 @@ public class DecryptFilesFragment extends DecryptFragment { } } + @Override + protected void onVerifyLoaded(boolean verified) { + + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 33209be86..d641f02f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -17,26 +17,49 @@ package org.sufficientlysecure.keychain.ui; +import java.util.ArrayList; + import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import org.openintents.openpgp.OpenPgpSignatureResult; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; +import org.sufficientlysecure.keychain.util.Preferences; + -public abstract class DecryptFragment extends CryptoOperationFragment { - private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; +public abstract class DecryptFragment extends CryptoOperationFragment implements + LoaderManager.LoaderCallbacks { - protected long mSignatureKeyId = 0; + public static final int LOADER_ID_UNIFIED = 0; protected LinearLayout mResultLayout; @@ -46,155 +69,118 @@ public abstract class DecryptFragment extends CryptoOperationFragment { protected TextView mSignatureText; protected View mSignatureLayout; - protected View mSignatureDivider1; - protected View mSignatureDivider2; protected TextView mSignatureName; protected TextView mSignatureEmail; protected TextView mSignatureAction; + private OpenPgpSignatureResult mSignatureResult; + @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); - mResultLayout = (LinearLayout) getView().findViewById(R.id.result_main_layout); + mResultLayout = (LinearLayout) view.findViewById(R.id.result_main_layout); mResultLayout.setVisibility(View.GONE); - mEncryptionIcon = (ImageView) getView().findViewById(R.id.result_encryption_icon); - mEncryptionText = (TextView) getView().findViewById(R.id.result_encryption_text); - mSignatureIcon = (ImageView) getView().findViewById(R.id.result_signature_icon); - mSignatureText = (TextView) getView().findViewById(R.id.result_signature_text); - mSignatureLayout = getView().findViewById(R.id.result_signature_layout); - mSignatureDivider1 = getView().findViewById(R.id.result_signature_divider1); - mSignatureDivider2 = getView().findViewById(R.id.result_signature_divider2); - mSignatureName = (TextView) getView().findViewById(R.id.result_signature_name); - mSignatureEmail = (TextView) getView().findViewById(R.id.result_signature_email); - mSignatureAction = (TextView) getView().findViewById(R.id.result_signature_action); + mEncryptionIcon = (ImageView) view.findViewById(R.id.result_encryption_icon); + mEncryptionText = (TextView) view.findViewById(R.id.result_encryption_text); + mSignatureIcon = (ImageView) view.findViewById(R.id.result_signature_icon); + mSignatureText = (TextView) view.findViewById(R.id.result_signature_text); + mSignatureLayout = view.findViewById(R.id.result_signature_layout); + mSignatureName = (TextView) view.findViewById(R.id.result_signature_name); + mSignatureEmail = (TextView) view.findViewById(R.id.result_signature_email); + mSignatureAction = (TextView) view.findViewById(R.id.result_signature_action); } private void lookupUnknownKey(long unknownKeyId) { - Intent intent = new Intent(getActivity(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId); - startActivityForResult(intent, RESULT_CODE_LOOKUP_KEY); - } - - private void showKey(long keyId) { - Intent viewKeyIntent = new Intent(getActivity(), ViewKeyActivity.class); - viewKeyIntent.setData(KeychainContract.KeyRings - .buildGenericKeyRingUri(keyId)); - startActivity(viewKeyIntent); - } - /** - * - * @return returns false if signature is invalid, key is revoked or expired. - */ - protected boolean onResult(DecryptVerifyResult decryptVerifyResult) { - final OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); + // Message is received after importing is done in KeychainIntentService + ServiceProgressHandler serviceHandler = new ServiceProgressHandler(getActivity()) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); - boolean valid = false; + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + // get returned data bundle + Bundle returnData = message.getData(); - mSignatureKeyId = 0; - mResultLayout.setVisibility(View.VISIBLE); - if (signatureResult != null) { - mSignatureKeyId = signatureResult.getKeyId(); - - String userId = signatureResult.getPrimaryUserId(); - KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId); - if (userIdSplit.name != null) { - mSignatureName.setText(userIdSplit.name); - } else { - mSignatureName.setText(R.string.user_id_no_name); - } - if (userIdSplit.email != null) { - mSignatureEmail.setText(userIdSplit.email); - } else { - mSignatureEmail.setText(KeyFormattingUtils.beautifyKeyIdWithPrefix(getActivity(), mSignatureKeyId)); - } + if (returnData == null) { + return; + } - if (signatureResult.isSignatureOnly()) { - mEncryptionText.setText(R.string.decrypt_result_not_encrypted); - KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.NOT_ENCRYPTED); - } else { - mEncryptionText.setText(R.string.decrypt_result_encrypted); - KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED); - } + final ImportKeyResult result = + returnData.getParcelable(OperationResult.EXTRA_RESULT); - switch (signatureResult.getStatus()) { - case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: { - mSignatureText.setText(R.string.decrypt_result_signature_certified); - KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.VERIFIED); + // if (!result.success()) { + result.createNotify(getActivity()).show(); + // } - setSignatureLayoutVisibility(View.VISIBLE); - setShowAction(mSignatureKeyId); + getLoaderManager().restartLoader(LOADER_ID_UNIFIED, null, DecryptFragment.this); - valid = true; - break; } + } + }; - case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: { - mSignatureText.setText(R.string.decrypt_result_signature_uncertified); - KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.UNVERIFIED); + // fill values for this action + Bundle data = new Bundle(); - setSignatureLayoutVisibility(View.VISIBLE); - setShowAction(mSignatureKeyId); + // search config + { + Preferences prefs = Preferences.getPreferences(getActivity()); + Preferences.CloudSearchPrefs cloudPrefs = + new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); + data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); + } - valid = true; - break; - } + { + ParcelableKeyRing keyEntry = new ParcelableKeyRing(null, + KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null); + ArrayList selectedEntries = new ArrayList<>(); + selectedEntries.add(keyEntry); - case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: { - mSignatureText.setText(R.string.decrypt_result_signature_missing_key); - KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.UNKNOWN_KEY); - - setSignatureLayoutVisibility(View.VISIBLE); - mSignatureAction.setText(R.string.decrypt_result_action_Lookup); - mSignatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_file_download_grey_24dp, 0); - mSignatureLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - lookupUnknownKey(mSignatureKeyId); - } - }); - - valid = true; - break; - } + data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, selectedEntries); + } - case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: { - mSignatureText.setText(R.string.decrypt_result_signature_expired_key); - KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.EXPIRED); + // Send all information needed to service to query keys in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - setSignatureLayoutVisibility(View.VISIBLE); - setShowAction(mSignatureKeyId); + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(serviceHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - valid = false; - break; - } + getActivity().startService(intent); - case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: { - mSignatureText.setText(R.string.decrypt_result_signature_revoked_key); - KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.REVOKED); + } - setSignatureLayoutVisibility(View.VISIBLE); - setShowAction(mSignatureKeyId); + private void showKey(long keyId) { + try { - valid = false; - break; - } + Intent viewKeyIntent = new Intent(getActivity(), ViewKeyActivity.class); + long masterKeyId = new ProviderHelper(getActivity()).getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId) + ).getMasterKeyId(); + viewKeyIntent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); + startActivity(viewKeyIntent); + + } catch (PgpKeyNotFoundException e) { + Notify.create(getActivity(), R.string.error_key_not_found, Style.ERROR); + } + } + + /** + * @return returns false if signature is invalid, key is revoked or expired. + */ + protected void loadVerifyResult(DecryptVerifyResult decryptVerifyResult) { - case OpenPgpSignatureResult.SIGNATURE_ERROR: { - mSignatureText.setText(R.string.decrypt_result_invalid_signature); - KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.INVALID); + mSignatureResult = decryptVerifyResult.getSignatureResult(); + mResultLayout.setVisibility(View.VISIBLE); - setSignatureLayoutVisibility(View.GONE); + // unsigned data + if (mSignatureResult == null) { - valid = false; - break; - } - } - } else { setSignatureLayoutVisibility(View.GONE); mSignatureText.setText(R.string.decrypt_result_no_signature); @@ -202,16 +188,27 @@ public abstract class DecryptFragment extends CryptoOperationFragment { mEncryptionText.setText(R.string.decrypt_result_encrypted); KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED); - valid = true; + getLoaderManager().destroyLoader(LOADER_ID_UNIFIED); + + onVerifyLoaded(true); + + return; + } + + if (mSignatureResult.isSignatureOnly()) { + mEncryptionText.setText(R.string.decrypt_result_not_encrypted); + KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.NOT_ENCRYPTED); + } else { + mEncryptionText.setText(R.string.decrypt_result_encrypted); + KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, State.ENCRYPTED); } - return valid; + getLoaderManager().restartLoader(LOADER_ID_UNIFIED, null, this); + } private void setSignatureLayoutVisibility(int visibility) { mSignatureLayout.setVisibility(visibility); - mSignatureDivider1.setVisibility(visibility); - mSignatureDivider2.setVisibility(visibility); } private void setShowAction(final long signatureKeyId) { @@ -225,4 +222,177 @@ public abstract class DecryptFragment extends CryptoOperationFragment { }); } + // These are the rows that we will retrieve. + static final String[] UNIFIED_PROJECTION = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_REVOKED, + KeychainContract.KeyRings.IS_EXPIRED, + KeychainContract.KeyRings.VERIFIED, + }; + + @SuppressWarnings("unused") + static final int INDEX_MASTER_KEY_ID = 1; + static final int INDEX_USER_ID = 2; + static final int INDEX_IS_REVOKED = 3; + static final int INDEX_IS_EXPIRED = 4; + static final int INDEX_VERIFIED = 5; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + if (id != LOADER_ID_UNIFIED) { + return null; + } + + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( + mSignatureResult.getKeyId()); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + + if (loader.getId() != LOADER_ID_UNIFIED) { + return; + } + + // If the key is unknown, show it as such + if (data.getCount() == 0 || !data.moveToFirst()) { + showUnknownKeyStatus(); + return; + } + + long signatureKeyId = mSignatureResult.getKeyId(); + + String userId = data.getString(INDEX_USER_ID); + KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId); + if (userIdSplit.name != null) { + mSignatureName.setText(userIdSplit.name); + } else { + mSignatureName.setText(R.string.user_id_no_name); + } + if (userIdSplit.email != null) { + mSignatureEmail.setText(userIdSplit.email); + } else { + mSignatureEmail.setText(KeyFormattingUtils.beautifyKeyIdWithPrefix( + getActivity(), mSignatureResult.getKeyId())); + } + + boolean isRevoked = data.getInt(INDEX_IS_REVOKED) != 0; + boolean isExpired = data.getInt(INDEX_IS_EXPIRED) != 0; + boolean isVerified = data.getInt(INDEX_VERIFIED) > 0; + + if (isRevoked) { + mSignatureText.setText(R.string.decrypt_result_signature_revoked_key); + KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.REVOKED); + + setSignatureLayoutVisibility(View.VISIBLE); + setShowAction(signatureKeyId); + + onVerifyLoaded(false); + + } else if (isExpired) { + mSignatureText.setText(R.string.decrypt_result_signature_expired_key); + KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.EXPIRED); + + setSignatureLayoutVisibility(View.VISIBLE); + setShowAction(signatureKeyId); + + onVerifyLoaded(true); + + } else if (isVerified) { + mSignatureText.setText(R.string.decrypt_result_signature_certified); + KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.VERIFIED); + + setSignatureLayoutVisibility(View.VISIBLE); + setShowAction(signatureKeyId); + + onVerifyLoaded(true); + + } else { + mSignatureText.setText(R.string.decrypt_result_signature_uncertified); + KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.UNVERIFIED); + + setSignatureLayoutVisibility(View.VISIBLE); + setShowAction(signatureKeyId); + + onVerifyLoaded(true); + } + + } + + @Override + public void onLoaderReset(Loader loader) { + + if (loader.getId() != LOADER_ID_UNIFIED) { + return; + } + + setSignatureLayoutVisibility(View.GONE); + + } + + private void showUnknownKeyStatus() { + + final long signatureKeyId = mSignatureResult.getKeyId(); + + int result = mSignatureResult.getStatus(); + if (result != OpenPgpSignatureResult.SIGNATURE_KEY_MISSING + && result != OpenPgpSignatureResult.SIGNATURE_ERROR) { + Log.e(Constants.TAG, "got missing status for non-missing key, shouldn't happen!"); + } + + String userId = mSignatureResult.getPrimaryUserId(); + KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId); + if (userIdSplit.name != null) { + mSignatureName.setText(userIdSplit.name); + } else { + mSignatureName.setText(R.string.user_id_no_name); + } + if (userIdSplit.email != null) { + mSignatureEmail.setText(userIdSplit.email); + } else { + mSignatureEmail.setText(KeyFormattingUtils.beautifyKeyIdWithPrefix( + getActivity(), mSignatureResult.getKeyId())); + } + + switch (mSignatureResult.getStatus()) { + + case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: { + mSignatureText.setText(R.string.decrypt_result_signature_missing_key); + KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.UNKNOWN_KEY); + + setSignatureLayoutVisibility(View.VISIBLE); + mSignatureAction.setText(R.string.decrypt_result_action_Lookup); + mSignatureAction + .setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_file_download_grey_24dp, 0); + mSignatureLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + lookupUnknownKey(signatureKeyId); + } + }); + + onVerifyLoaded(true); + + break; + } + + case OpenPgpSignatureResult.SIGNATURE_ERROR: { + mSignatureText.setText(R.string.decrypt_result_invalid_signature); + KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, State.INVALID); + + setSignatureLayoutVisibility(View.GONE); + + onVerifyLoaded(false); + break; + } + + } + + } + + protected abstract void onVerifyLoaded(boolean verified); + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 9c6c89c43..1b9ae917f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -23,6 +23,9 @@ import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -39,7 +42,6 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ShareHelper; import java.io.UnsupportedEncodingException; @@ -54,6 +56,7 @@ public class DecryptTextFragment extends DecryptFragment { // model private String mCiphertext; + private boolean mShowMenuOptions = false; /** * Creates new instance of this fragment @@ -79,22 +82,6 @@ public class DecryptTextFragment extends DecryptFragment { mInvalidLayout = (LinearLayout) view.findViewById(R.id.decrypt_text_invalid); mText = (TextView) view.findViewById(R.id.decrypt_text_plaintext); - View vShareButton = view.findViewById(R.id.action_decrypt_share_plaintext); - vShareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startActivity(sendWithChooserExcludingEncrypt(mText.getText().toString())); - } - }); - - View vCopyButton = view.findViewById(R.id.action_decrypt_copy_plaintext); - vCopyButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - copyToClipboard(mText.getText().toString()); - } - }); - Button vInvalidButton = (Button) view.findViewById(R.id.decrypt_text_invalid_button); vInvalidButton.setOnClickListener(new View.OnClickListener() { @Override @@ -139,6 +126,8 @@ public class DecryptTextFragment extends DecryptFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + String ciphertext = getArguments().getString(ARG_CIPHERTEXT); if (ciphertext != null) { mCiphertext = ciphertext; @@ -146,6 +135,33 @@ public class DecryptTextFragment extends DecryptFragment { } } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + if (mShowMenuOptions) { + inflater.inflate(R.menu.decrypt_menu, menu); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.decrypt_share: { + startActivity(sendWithChooserExcludingEncrypt(mText.getText().toString())); + break; + } + case R.id.decrypt_copy: { + copyToClipboard(mText.getText().toString()); + break; + } + default: { + return super.onOptionsItemSelected(item); + } + } + + return true; + } + @Override protected void cryptoOperation(CryptoInputParcel cryptoInput) { // Send all information needed to service to decrypt in other thread @@ -206,15 +222,8 @@ public class DecryptTextFragment extends DecryptFragment { pgpResult.createNotify(getActivity()).show(); // display signature result in activity - boolean valid = onResult(pgpResult); + loadVerifyResult(pgpResult); - if (valid) { - mInvalidLayout.setVisibility(View.GONE); - mValidLayout.setVisibility(View.VISIBLE); - } else { - mInvalidLayout.setVisibility(View.VISIBLE); - mValidLayout.setVisibility(View.GONE); - } } else { pgpResult.createNotify(getActivity()).show(); // TODO: show also invalid layout with different text? @@ -234,4 +243,19 @@ public class DecryptTextFragment extends DecryptFragment { getActivity().startService(intent); } + @Override + protected void onVerifyLoaded(boolean verified) { + + mShowMenuOptions = verified; + getActivity().supportInvalidateOptionsMenu(); + + if (verified) { + mInvalidLayout.setVisibility(View.GONE); + mValidLayout.setVisibility(View.VISIBLE); + } else { + mInvalidLayout.setVisibility(View.VISIBLE); + mValidLayout.setVisibility(View.GONE); + } + + } } diff --git a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml index debc1106f..f64d72987 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml @@ -1,10 +1,12 @@ + android:background="@color/holo_gray_bright" + tools:showIn="@layout/decrypt_text_fragment"> + android:paddingBottom="4dp" + android:animateLayoutChanges="true"> + android:layout_marginBottom="8dp" + tools:text="Encryption status text" + /> + android:layout_marginBottom="8dp" + tools:text="Signature status text" + /> - - @@ -83,6 +81,7 @@ android:layout_height="match_parent" android:layout_weight="1" android:paddingRight="4dp" + android:paddingLeft="4dp" android:gravity="center_vertical" android:orientation="vertical"> @@ -91,15 +90,16 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="Alice (set in-code)" /> + tools:text="Alice" /> + android:gravity="center_vertical" + tools:text="alice@example.com" + /> @@ -114,6 +114,7 @@ + /> - - - - - - - - - - - - - - + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index df88336a1..4d92dac20 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -78,7 +78,8 @@ "View certification key" "Create key" "Add file(s)" - "Share decrypted text" + "Share decrypted text" + "Copy decrypted text" "Decrypt text from clipboard" "and verify signatures" "Decrypt files" @@ -285,16 +286,16 @@ "Not Signed" "Invalid signature!" - "Signed by (not certified!)" - "Signed by" - "Key is expired!" - "Key has been revoked!" - "Unknown public key" + "Signed by unconfirmed key" + "Signed by confirmed key" + "Signed by expired key!" + "Signed by revoked key!" + "Signed by unknown public key" "Encrypted" "Not Encrypted" "Show" "Lookup" - "Either the signature is invalid or the key has been revoked/is expired. You cannot be sure who wrote the text. Do you still want to display it?" + "Either the signature is invalid or the key has been revoked. You cannot be sure who wrote the text. Do you still want to display it?" "I understand the risks, display it!" -- cgit v1.2.3 From 9c174ff71dd5cf0bfdb1ae22d41abeda25eef913 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 24 Apr 2015 19:16:15 +0200 Subject: fix encrypt activity layout --- .../keychain/ui/widget/EncryptKeyCompletionView.java | 3 +-- OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java index b2dfb2493..3d2e8b9df 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java @@ -108,9 +108,8 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView protected void onAttachedToWindow() { super.onAttachedToWindow(); - mLoaderManager = ((FragmentActivity) getContext()).getSupportLoaderManager(); - if (getContext() instanceof FragmentActivity) { + mLoaderManager = ((FragmentActivity) getContext()).getSupportLoaderManager(); mLoaderManager.initLoader(hashCode(), null, this); } else { Log.e(Constants.TAG, "EncryptKeyCompletionView must be attached to a FragmentActivity, this is " + getContext().getClass()); diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml index 51891155c..aa295050a 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml @@ -11,6 +11,8 @@ android:id="@+id/recipient_list" android:layout_width="match_parent" android:minHeight="56dip" + android:paddingLeft="8dp" + android:paddingRight="8dp" android:layout_height="wrap_content" /> Date: Sat, 25 Apr 2015 14:06:53 +0200 Subject: Remove old navigation drawer dependency --- OpenKeychain/build.gradle | 3 --- OpenKeychain/src/main/res/values/colors.xml | 1 + OpenKeychain/src/main/res/values/themes.xml | 9 --------- 3 files changed, 1 insertion(+), 12 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index 6341766f9..c47e650cb 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -17,7 +17,6 @@ dependencies { compile 'com.journeyapps:zxing-android-integration:2.3.0@aar' compile 'com.google.zxing:core:3.2.0' compile 'com.jpardogo.materialtabstrip:library:1.0.9' - compile 'it.neokree:MaterialNavigationDrawer:1.3.2' compile 'com.getbase:floatingactionbutton:1.9.0' compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.0' compile "com.splitwise:tokenautocomplete:1.3.3@aar" @@ -55,7 +54,6 @@ dependencyVerification { 'com.journeyapps:zxing-android-integration:562737821b6d34c899b6fd2234ce0a8a31e02ff1fd7c59f6211961ce9767c7c8', 'com.google.zxing:core:7fe5a8ff437635a540e56317649937b768b454795ce999ed5f244f83373dee7b', 'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa', - 'it.neokree:MaterialNavigationDrawer:a1221a410c5f71bf078c5c4768fdf06b402d6006c74f8e7b61199e4edc2aea57', 'com.getbase:floatingactionbutton:052aa2a94e49e5dccc97cb99f2add87e8698b84859f0e3ac181100c0bc7640ca', 'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13', 'com.splitwise:tokenautocomplete:20bee71cc59b3828eb000b684d46ddf738efd56b8fee453a509cd16fda42c8cb', @@ -77,7 +75,6 @@ dependencyVerification { // 'OpenKeychain.extern:safeslinger-exchange:d222721bb35408daaab9f46449364b2657112705ee571d7532f81cbeb9c4a73f', // 'OpenKeychain.extern.snackbar:lib:52357426e5275412e2063bdf6f0e6b957a3ea74da45e0aef35d22d9afc542e23', 'com.android.support:support-annotations:ab6b131ab0e1edd165d21fb4c3edadeacbee9539aa166f7f7cbae05b60dc207a', - 'com.balysv:material-ripple:b2580520bcb5e5d77bd8c42b030317accaf8f88e7e57c46a29c47c8a62d4ff45', ] } diff --git a/OpenKeychain/src/main/res/values/colors.xml b/OpenKeychain/src/main/res/values/colors.xml index 8c5358fd0..ead006a63 100644 --- a/OpenKeychain/src/main/res/values/colors.xml +++ b/OpenKeychain/src/main/res/values/colors.xml @@ -22,6 +22,7 @@ #727272 #FFFFFF #B6B6B6 + #00FFFFFF #212121 diff --git a/OpenKeychain/src/main/res/values/themes.xml b/OpenKeychain/src/main/res/values/themes.xml index c87895c01..a1644707e 100644 --- a/OpenKeychain/src/main/res/values/themes.xml +++ b/OpenKeychain/src/main/res/values/themes.xml @@ -15,19 +15,10 @@ true @style/MySearchViewStyle - - @integer/DRAWERTYPE_IMAGE @style/ThemeOverlay.AppCompat.Dark @style/ThemeOverlay.AppCompat.Light - #fafafa - false - @style/MaterialSectionTheme.Light - @style/MaterialSubheaderTheme.Light - false - false - false -- cgit v1.2.3 From f8af6e3387b46bf0be3dbef799de483e090ad850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 25 Apr 2015 14:09:55 +0200 Subject: Update lib section in about --- OpenKeychain/src/main/res/raw/help_about.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/res/raw/help_about.md b/OpenKeychain/src/main/res/raw/help_about.md index 4b51c1695..41e8d9542 100644 --- a/OpenKeychain/src/main/res/raw/help_about.md +++ b/OpenKeychain/src/main/res/raw/help_about.md @@ -39,8 +39,8 @@ License: GPLv3+ * [ZXing](https://github.com/zxing/zxing) (Apache License v2) * [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Apache License v2) * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2) - * [MaterialNavigationDrawer](https://github.com/neokree/MaterialNavigationDrawer) (Apache License v2) + * [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2) * [Snackbar](https://github.com/nispok/snackbar) (MIT License) * [FloatingActionButton](https://github.com/futuresimple/android-floating-action-button) (Apache License v2) - * [HtmlTextView](https://github.com/dschuermann/html-textview) (Apache License v2) + * [HtmlTextView](https://github.com/sufficientlysecure/html-textview) (Apache License v2) * [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2) -- cgit v1.2.3 From 28da73120145078eae9a62cb98fc9d704d5ef7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 25 Apr 2015 14:15:38 +0200 Subject: Fix empty screen when clicking on encrypt in details view --- .../org/sufficientlysecure/keychain/ui/EncryptTextActivity.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 03ab48e23..dd6dd6594 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -98,23 +98,20 @@ public class EncryptTextActivity extends BaseActivity implements // handle like normal text encryption, override action and extras to later // executeServiceMethod ACTION_ENCRYPT_TEXT in main actions extras.putString(EXTRA_TEXT, sharedText); - action = ACTION_ENCRYPT_TEXT; } } } String textData = extras.getString(EXTRA_TEXT); - if (ACTION_ENCRYPT_TEXT.equals(action) && textData == null) { - Log.e(Constants.TAG, "Include the extra 'text' in your Intent!"); - return; + if (textData == null) { + textData = ""; } // preselect keys given by intent long mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); long[] mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); - if (savedInstanceState == null) { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); -- cgit v1.2.3 From 64ca19464b50cf14193e25724eaadd229b1a86ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 25 Apr 2015 14:37:55 +0200 Subject: Set different titles when changing in nav drawer --- .../org/sufficientlysecure/keychain/ui/MainActivity.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index fa4f07d88..151382da3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -49,7 +49,8 @@ public class MainActivity extends ActionBarActivity implements FabContainer { private KeyListFragment mKeyListFragment ; private AppsListFragment mAppsListFragment; private EncryptDecryptOverviewFragment mEncryptDecryptOverviewFragment; - private Fragment lastUsedFragment; + private Fragment mLastUsedFragment; + private Toolbar mToolbar; @Override public void onCreate(Bundle savedInstanceState) { @@ -63,14 +64,14 @@ public class MainActivity extends ActionBarActivity implements FabContainer { transaction.replace(R.id.main_fragment_container, mainFragment); transaction.commit(); - final Toolbar toolbar = (Toolbar) findViewById(R.id.activity_main_toolbar); - toolbar.setTitle(R.string.app_name); - setSupportActionBar(toolbar); + mToolbar = (Toolbar) findViewById(R.id.activity_main_toolbar); + mToolbar.setTitle(R.string.app_name); + setSupportActionBar(mToolbar); result = new Drawer() .withActivity(this) .withHeader(R.layout.main_drawer_header) - .withToolbar(toolbar) + .withToolbar(mToolbar) .addDrawerItems( new PrimaryDrawerItem().withName(R.string.nav_keys).withIcon(CommunityMaterial.Icon.cmd_key).withIdentifier(1).withCheckable(false), new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock).withIdentifier(2).withCheckable(false), @@ -144,7 +145,7 @@ public class MainActivity extends ActionBarActivity implements FabContainer { } private void setFragment(Fragment fragment, boolean addToBackStack) { - this.lastUsedFragment = fragment; + this.mLastUsedFragment = fragment; FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.main_fragment_container, fragment); if (addToBackStack) { @@ -154,6 +155,7 @@ public class MainActivity extends ActionBarActivity implements FabContainer { } private boolean onKeysSelected() { + mToolbar.setTitle(R.string.app_name); clearFragments(); if (mKeyListFragment == null) { @@ -165,6 +167,7 @@ public class MainActivity extends ActionBarActivity implements FabContainer { } private boolean onEnDecryptSelected() { + mToolbar.setTitle(R.string.nav_encrypt_decrypt); clearFragments(); if (mEncryptDecryptOverviewFragment == null) { mEncryptDecryptOverviewFragment = new EncryptDecryptOverviewFragment(); @@ -175,6 +178,7 @@ public class MainActivity extends ActionBarActivity implements FabContainer { } private boolean onAppsSelected() { + mToolbar.setTitle(R.string.nav_apps); clearFragments(); if (mAppsListFragment == null) { mAppsListFragment = new AppsListFragment(); -- cgit v1.2.3 From 5d6eb2930cc785b7f1c88fa687cd5bc844c065d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 25 Apr 2015 15:10:15 +0200 Subject: Update in-app contributor list --- OpenKeychain/src/main/res/raw/help_about.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/res/raw/help_about.md b/OpenKeychain/src/main/res/raw/help_about.md index 41e8d9542..65a04e56e 100644 --- a/OpenKeychain/src/main/res/raw/help_about.md +++ b/OpenKeychain/src/main/res/raw/help_about.md @@ -6,8 +6,12 @@ License: GPLv3+ -## Developers +## Main Developers * Dominik Schürmann (Maintainer) + * Vincent Breitmoser + +## Contributors + * Adithya Abraham Philip * Art O Cathain * Ash Hughes * Brian C. Barnes @@ -15,18 +19,33 @@ License: GPLv3+ * Daniel Albert * Daniel Hammann * Daniel Haß + * Daniel Nelz + * Daniel Ramos * Greg Witczak + * 'iseki' + * Ishan Khanna + * 'jellysheep' + * 'Jesperbk' + * 'jkolo' + * Joey Castillo + * Kai Jiang + * Kartik Arora + * 'Kent' + * 'ligi' + * Lukas Zorich + * Manoj Khanna * 'mar-v-in' * Markus Doits * Miroojin Bakshi + * Morgan Gangwere * Nikhil Peter Raj * Paul Sarbinowski * 'Senecaso' * Signe Rüsch * Sreeram Boyapati - * Thialfihar (APG 1.x) + * 'steelman' + * 'Thialfihar' (APG developer) * Tim Bray - * Vincent Breitmoser ## Libraries * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License) -- cgit v1.2.3 From f1f0126048a66b3e649f35f2e2768bd43fe1fad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 25 Apr 2015 23:40:26 +0200 Subject: Switch to new support lib version 22.1 --- OpenKeychain/build.gradle | 18 +- .../keychain/ui/MainActivity.java | 4 +- .../keychain/ui/adapter/PagerTabStripAdapter.java | 4 +- .../keychain/ui/adapter/TabsAdapter.java | 4 +- .../keychain/ui/base/BaseActivity.java | 4 +- .../keychain/ui/widget/EmailEditText.java | 12 +- .../keychain/ui/widget/KeySpinner.java | 6 +- .../keychain/ui/widget/NameEditText.java | 12 +- .../keychain/ui/widget/PassphraseEditText.java | 6 +- .../ui/widget/PasswordStrengthBarView.java | 114 +++++++ .../keychain/ui/widget/PasswordStrengthView.java | 361 ++++++++++++++++++++ .../PasswordStrengthBarView.java | 117 ------- .../PasswordStrengthView.java | 362 --------------------- .../main/res/layout/passphrase_repeat_dialog.xml | 2 +- OpenKeychain/src/main/res/values/themes.xml | 2 +- 15 files changed, 503 insertions(+), 525 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthBarView.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java (limited to 'OpenKeychain') diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index c47e650cb..09f3b589e 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -6,10 +6,10 @@ dependencies { // NOTE: libraries are pinned to a specific build, see below // from local Android SDK - compile 'com.android.support:support-v4:22.0.0' - compile 'com.android.support:appcompat-v7:22.0.0' - compile 'com.android.support:recyclerview-v7:22.0.0' - compile 'com.android.support:cardview-v7:22.0.0' + compile 'com.android.support:support-v4:22.1.0' + compile 'com.android.support:appcompat-v7:22.1.0' + compile 'com.android.support:recyclerview-v7:22.1.0' + compile 'com.android.support:cardview-v7:22.1.0' // JCenter etc. compile 'com.eftimoff:android-patternview:1.0.1@aar' @@ -45,10 +45,10 @@ dependencies { // Comment out the libs referenced as git submodules! dependencyVerification { verify = [ - 'com.android.support:support-v4:355a11466727e8ba00e239416aec55ac3cd3fb4ffc9d20c4a33373085c050bd1', - 'com.android.support:appcompat-v7:40114cb756fecffa4a51c5645593cf64509c576594f77e41e801368051115c7b', - 'com.android.support:recyclerview-v7:859ed80e3761f8fc3126901260b208505120b5678bcf36ad2cfe9c453958b9c7', - 'com.android.support:cardview-v7:4c03f2acce9925aa4f8845cb8cb37b3772c712b2438ff15f76c9e3d3bc63ead7', + 'com.android.support:support-v4:74cb322740317b11a785eee1a94969426fade946123c4ae3f471276adaaaf54b', + 'com.android.support:appcompat-v7:6cc7fc2df4be0676f78ecfc5d3cda388e59890d11308811944f54efd84b047b7', + 'com.android.support:recyclerview-v7:522d323079a29bcd76173bd9bc7535223b4af3e5eefef9d9287df1f9e54d0c10', + 'com.android.support:cardview-v7:8dc99af71fec000baa4470c3907755264f15f816920861bc015b2babdbb49807', 'com.eftimoff:android-patternview:cec80e7265b8d8278b3c55b5fcdf551e4600ac2c8bf60d8dd76adca538af0b1e', 'com.journeyapps:zxing-android-embedded:702a4f58154dbd9baa80f66b6a15410f7a4d403f3e73b66537a8bfb156b4b718', 'com.journeyapps:zxing-android-integration:562737821b6d34c899b6fd2234ce0a8a31e02ff1fd7c59f6211961ce9767c7c8', @@ -74,7 +74,7 @@ dependencyVerification { // 'OpenKeychain.extern.KeybaseLib:Lib:c91cda4a75692d8664644cd17d8ac962ce5bc0e266ea26673a639805f1eccbdf', // 'OpenKeychain.extern:safeslinger-exchange:d222721bb35408daaab9f46449364b2657112705ee571d7532f81cbeb9c4a73f', // 'OpenKeychain.extern.snackbar:lib:52357426e5275412e2063bdf6f0e6b957a3ea74da45e0aef35d22d9afc542e23', - 'com.android.support:support-annotations:ab6b131ab0e1edd165d21fb4c3edadeacbee9539aa166f7f7cbae05b60dc207a', + 'com.android.support:support-annotations:9c59286413a2bb93e199c73261e58d5af32da7ae0a12cbd075f581a5de1fb446', ] } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 151382da3..05cf64092 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -24,7 +24,7 @@ import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.AdapterView; @@ -42,7 +42,7 @@ import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; import org.sufficientlysecure.keychain.util.FabContainer; import org.sufficientlysecure.keychain.util.Preferences; -public class MainActivity extends ActionBarActivity implements FabContainer { +public class MainActivity extends AppCompatActivity implements FabContainer { public Drawer.Result result; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java index 963e77fe9..7b911da96 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java @@ -21,7 +21,7 @@ import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import java.util.ArrayList; @@ -41,7 +41,7 @@ public class PagerTabStripAdapter extends FragmentPagerAdapter { } } - public PagerTabStripAdapter(ActionBarActivity activity) { + public PagerTabStripAdapter(AppCompatActivity activity) { super(activity.getSupportFragmentManager()); mActivity = activity; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java index 44afed351..a1f00599c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java @@ -24,7 +24,7 @@ import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import java.util.ArrayList; @@ -45,7 +45,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar. } } - public TabsAdapter(ActionBarActivity activity, ViewPager pager) { + public TabsAdapter(AppCompatActivity activity, ViewPager pager) { super(activity.getSupportFragmentManager()); mContext = activity; mActionBar = activity.getSupportActionBar(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java index 07d2ef8c0..0e752881f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java @@ -20,7 +20,7 @@ package org.sufficientlysecure.keychain.ui.base; import android.app.Activity; import android.os.Bundle; import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Gravity; import android.view.LayoutInflater; @@ -33,7 +33,7 @@ import org.sufficientlysecure.keychain.R; /** * Setups Toolbar */ -public abstract class BaseActivity extends ActionBarActivity { +public abstract class BaseActivity extends AppCompatActivity { protected Toolbar mToolbar; protected View mStatusBar; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java index e21c5d510..e55f6b1ad 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java @@ -17,9 +17,8 @@ package org.sufficientlysecure.keychain.ui.widget; -import android.annotation.TargetApi; import android.content.Context; -import android.os.Build; +import android.support.v7.widget.AppCompatAutoCompleteTextView; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; @@ -27,14 +26,13 @@ import android.util.AttributeSet; import android.util.Patterns; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.ContactHelper; import java.util.regex.Matcher; -public class EmailEditText extends AutoCompleteTextView { +public class EmailEditText extends AppCompatAutoCompleteTextView { public EmailEditText(Context context) { super(context); @@ -51,12 +49,6 @@ public class EmailEditText extends AutoCompleteTextView { init(); } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(); - } - private void init() { setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); reenableKeyboardSuggestions(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java index 2c75c3a7d..fc5ecd76a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java @@ -24,7 +24,7 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; -import android.support.v7.internal.widget.TintSpinner; +import android.support.v7.widget.AppCompatSpinner; import android.text.format.DateFormat; import android.util.AttributeSet; import android.view.View; @@ -46,10 +46,10 @@ import java.util.Date; import java.util.TimeZone; /** - * Use TintSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon. + * Use AppCompatSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon. * Related: http://stackoverflow.com/a/27713090 */ -public abstract class KeySpinner extends TintSpinner implements LoaderManager.LoaderCallbacks { +public abstract class KeySpinner extends AppCompatSpinner implements LoaderManager.LoaderCallbacks { public interface OnKeyChangedListener { public void onKeyChanged(long masterKeyId); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java index 153bf2ff2..1a034537c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java @@ -17,17 +17,15 @@ package org.sufficientlysecure.keychain.ui.widget; -import android.annotation.TargetApi; import android.content.Context; -import android.os.Build; +import android.support.v7.widget.AppCompatAutoCompleteTextView; import android.util.AttributeSet; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; import org.sufficientlysecure.keychain.util.ContactHelper; -public class NameEditText extends AutoCompleteTextView { +public class NameEditText extends AppCompatAutoCompleteTextView { public NameEditText(Context context) { super(context); init(); @@ -43,12 +41,6 @@ public class NameEditText extends AutoCompleteTextView { init(); } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public NameEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(); - } - private void init() { reenableKeyboardSuggestions(); initAdapter(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java index 377f701d1..9364c5ee9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java @@ -19,15 +19,13 @@ package org.sufficientlysecure.keychain.ui.widget; import android.content.Context; import android.graphics.Canvas; +import android.support.v7.widget.AppCompatEditText; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; import android.util.TypedValue; -import android.widget.EditText; -import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthBarView; - -public class PassphraseEditText extends EditText { +public class PassphraseEditText extends AppCompatEditText { PasswordStrengthBarView mPasswordStrengthBarView; int mPasswordBarWidth; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthBarView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthBarView.java new file mode 100644 index 000000000..e5886345f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthBarView.java @@ -0,0 +1,114 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014 Matt Allen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.sufficientlysecure.keychain.ui.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; + +/** + * Created by matt on 04/07/2014. + * https://github.com/matt-allen/android-password-strength-indicator + */ +public class PasswordStrengthBarView extends PasswordStrengthView { + + public PasswordStrengthBarView(Context context, AttributeSet attrs) { + super(context, attrs); + mMinHeight = 80; + mMinWidth = 300; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + generateIndicatorColor(); + // Default to full width + int indWidth = mIndicatorWidth; + // If score, leave it as full - can cause it to become + // less than full width in this calculation + if (mCurrentScore < 20) indWidth = (mIndicatorWidth / 20) * mCurrentScore; + // Draw indicator + canvas.drawRect( + getPaddingLeft(), + getPaddingTop(), + indWidth, + mIndicatorHeight, + mIndicatorPaint + ); + // Draw guides if true + if (mShowGuides) { + // TODO: Try and do this with a loop, for efficiency + // Draw bottom guide border + float positionY = getHeight() - getPaddingBottom() - getPaddingTop(); + float notchHeight = (float) (positionY * 0.8); + canvas.drawLine( + getPaddingLeft(), + positionY, + getWidth() - getPaddingRight(), + positionY, + mGuidePaint); + // Show left-most notch + canvas.drawLine( + getPaddingLeft(), + positionY, + getPaddingLeft(), + notchHeight, + mGuidePaint + ); + // Show middle-left notch + canvas.drawLine( + (float) (mIndicatorWidth * 0.25) + getPaddingLeft(), + positionY, + (float) (mIndicatorWidth * 0.25) + getPaddingLeft(), + notchHeight, + mGuidePaint + ); + // Show the middle notch + canvas.drawLine( + (float) (mIndicatorWidth * 0.5) + getPaddingLeft(), + positionY, + (float) (mIndicatorWidth * 0.5) + getPaddingLeft(), + notchHeight, + mGuidePaint + ); + // Show the middle-right notch + canvas.drawLine( + (float) (mIndicatorWidth * 0.75) + getPaddingLeft(), + positionY, + (float) (mIndicatorWidth * 0.75) + getPaddingLeft(), + notchHeight, + mGuidePaint + ); + // Show the right-most notch + canvas.drawLine( + mIndicatorWidth + getPaddingLeft(), + positionY, + mIndicatorWidth + getPaddingLeft(), + notchHeight, + mGuidePaint + ); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java new file mode 100644 index 000000000..1487c3053 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java @@ -0,0 +1,361 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014 Matt Allen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.sufficientlysecure.keychain.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.View; + +import org.sufficientlysecure.keychain.R; + +/** + * Created by Matt Allen + * 01/07/14 + * http://www.mattallensoftware.co.uk + * mattallen092@gmail.com + *

+ * https://github.com/matt-allen/android-password-strength-indicator + *

+ *

+ * This View is designed to indicate how secure a user-entered password is in a visual way to + * relay to the user if they need to make it stronger. The strength of the password can be set + * at creation (or after) which will decide whether their password is strong enough. + *

+ *

+ *

+ * The password strength is decided by an index of 20. The minimum score needed to pass is 10 + * which means the String has met the conditions imposed by the strength test, but can be improved. + * If the password scores 10-19 it is considered weak, and only if it scores 20 will it be + * considered strong. + *

+ */ +public class PasswordStrengthView extends View { + + protected int mMinWidth; + protected int mMinHeight; + + protected Paint mIndicatorPaint; + protected Paint mGuidePaint; + + protected int mIndicatorHeight; + protected int mIndicatorWidth; + protected int mCurrentScore; + + protected int mColorFail; + protected int mColorWeak; + protected int mColorStrong; + + protected boolean mShowGuides = true; + + /** + * Used to define that the indicator should only be looking + * for a weak password. The bare minimum is used here to let + * the user continue. + */ + public static final int STRENGTH_WEAK = 0; + + /** + * A fairly strict rule for generating a password. It encourages a password that is + * less easy to crack. + */ + public static final int STRENGTH_MEDIUM = 1; + + /** + * A strong algorithm that encourages very strong passwords that should be fairly long, with + * non-alphanumeric, numbers, and upper case. + */ + public static final int STRENGTH_STRONG = 2; + + private int mStrengthRequirement = -1; + protected String mPassword; + + public PasswordStrengthView(Context context, AttributeSet attrs) { + super(context, attrs); + + int COLOR_FAIL = context.getResources().getColor(R.color.android_red_light); + int COLOR_WEAK = context.getResources().getColor(R.color.android_orange_light); + int COLOR_STRONG = context.getResources().getColor(R.color.android_green_light); + + TypedArray style = context.getTheme().obtainStyledAttributes( + attrs, + R.styleable.PasswordStrengthView, + 0, 0); + + try { + mStrengthRequirement = style.getInteger(R.styleable.PasswordStrengthView_strength, + STRENGTH_MEDIUM); + mShowGuides = style.getBoolean(R.styleable.PasswordStrengthView_showGuides, true); + mColorFail = style.getColor(R.styleable.PasswordStrengthView_color_fail, COLOR_FAIL); + mColorWeak = style.getColor(R.styleable.PasswordStrengthView_color_weak, COLOR_WEAK); + mColorStrong = style.getColor(R.styleable.PasswordStrengthView_color_strong, + COLOR_STRONG); + } catch (Exception e) { + e.printStackTrace(); + } + // Create and style the paint used for drawing the guide on the indicator + mGuidePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mGuidePaint.setStyle(Paint.Style.FILL_AND_STROKE); + mGuidePaint.setColor(Color.BLACK); + // Create and style paint for indicator + mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mIndicatorPaint.setStyle(Paint.Style.FILL); + } + + /** + * This view can determine if the password entered by the user is acceptable for + * use by your use case. This is based on the strength requirement you have set. + * + * @return True if requirement has been met + */ + public boolean isStrengthRequirementMet() { + return (mCurrentScore >= 10); + } + + /** + * Change the strength requirement of the password entered by the user. This will also + * re-check the password already entered against these new requirements. + * + * @param requiredStrength Use the public constants of this class to set + */ + public void setStrengthRequirement(int requiredStrength) { + if (requiredStrength >= 0 && requiredStrength <= 2) { + mStrengthRequirement = requiredStrength; + if (mPassword != null && mPassword.length() > 0) { + generatePasswordScore(); + // Update view with new score + invalidate(); + requestLayout(); + } + } else { + throw new IndexOutOfBoundsException("Input out of expected range"); + } + } + + /** + * Update the password string to check strength of + * + * @param passwordString String representation of user-input + */ + public void setPassword(String passwordString) { + if (passwordString != null && passwordString.length() > 0) { + mPassword = passwordString; + generatePasswordScore(); + } else { + mPassword = ""; + mCurrentScore = 0; + } + + // Update view with new score + invalidate(); + requestLayout(); + } + + /** + * Private convenience method for adding to the password score + * + * @param score Amount to be added to current score + */ + protected void addToPasswordScore(int score) { + int newScore = mCurrentScore + score; + + // Limit max score + if (newScore > 20) { + mCurrentScore = 20; + } else { + mCurrentScore = newScore; + } + } + + /** + * Call this to determine the current strength requirement set on the algorithm + * + * @return Int representation of the current strength set for the indicator + */ + public int getStrengthRequirement() { + return mStrengthRequirement; + } + + /** + * Generate a score based on the password. The password will already need to be stored + * as a class member before running this. + */ + protected void generatePasswordScore() { + mCurrentScore = 0; + int upperCase = getUppercaseCount(mPassword); + int nonAlpha = getNonAlphanumericCount(mPassword); + int numbers = getNumberCount(mPassword); + switch (mStrengthRequirement) { + case STRENGTH_WEAK: + addToPasswordScore(mPassword.length() * 2); + addToPasswordScore(upperCase * 2); + addToPasswordScore(nonAlpha * 2); + addToPasswordScore(numbers * 2); + break; + + case STRENGTH_MEDIUM: + addToPasswordScore(mPassword.length()); + addToPasswordScore(upperCase); + addToPasswordScore(nonAlpha * 2); + addToPasswordScore(numbers); + break; + + case STRENGTH_STRONG: + addToPasswordScore(mPassword.length() / 2); + // Cut the score in half to make this a very high requirement + addToPasswordScore(upperCase); + addToPasswordScore(nonAlpha); + addToPasswordScore(numbers); + break; + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldW, int oldH) { + super.onSizeChanged(w, h, oldW, oldH); + int paddingX = getPaddingLeft(); + int paddingY = getPaddingTop(); + mIndicatorHeight = h - paddingY; + mIndicatorWidth = w - paddingX; + } + + /** + * The standard parts of the onMeasure needed to create the password strength + * indicator. Subclasses should call super.onMeasure, but also need to set + * the minimum height and width in the constructor. + * + * @param widthMeasureSpec The measurement given by the system + * @param heightMeasureSpec The measurement given by the system + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Set minimum space for the view to do it's thing + int minW = getPaddingLeft() + getPaddingRight() + mMinWidth; + int w = resolveSizeAndState(minW, widthMeasureSpec, 1); + // And give it enough height so it's visible + int minH = mMinHeight + getPaddingBottom() + getPaddingTop(); + int h = resolveSizeAndState(minH, heightMeasureSpec, 0); + // Feed these back into UIKit + setMeasuredDimension(w, h); + } + + /** + * Set the colour of the indicator {@code Paint} to one that is appropriate + * for the strength of the password. + */ + protected void generateIndicatorColor() { + int color = mColorFail; + if (mCurrentScore >= 18) { + color = mColorStrong; + } else if (mCurrentScore >= 10) { + color = mColorWeak; + } + mIndicatorPaint.setColor(color); + } + + /** + * Quick method to determine how many of the characters in a given string are upper case + * + * @param stringToCheck The string to examine + * @return Number of upper case characters + */ + protected int getUppercaseCount(String stringToCheck) { + int score = 0; + int loops = stringToCheck.length() - 1; + for (int i = 0; i <= loops; i++) { + if (Character.isUpperCase(stringToCheck.charAt(i))) { + score++; + } + } + return score; + } + + /** + * A convenience method to determine how many characters in the given String aren't + * letters or numbers. + * + * @param stringToCheck + * @return Number of characters that aren't numbers or letters + */ + protected int getNonAlphanumericCount(String stringToCheck) { + int score = 0; + int loops = stringToCheck.length() - 1; + for (int i = 0; i <= loops; i++) { + if (!Character.isLetter(stringToCheck.charAt(i)) && + !Character.isDigit(stringToCheck.charAt(i))) { + score++; + } + } + return score; + } + + /** + * A convenience method for returning the count of numbers in a given String. + * + * @param stringToCheck + * @return The numbers of digits in the String + */ + protected int getNumberCount(String stringToCheck) { + int score = 0; + int loops = stringToCheck.length() - 1; + for (int i = 0; i <= loops; i++) { + if (Character.isDigit(stringToCheck.charAt(i))) { + score++; + } + } + return score; + } + + /** + * Set the guides to show on the view.
+ * On the line style, the guides will show underneath
+ * On the rounded style, the guides will be shown on the outer edges.
+ * The view will be redrawn after the method is called. + * + * @param showGuides True if you want the guides to be shown + */ + public void setShowGuides(boolean showGuides) { + mShowGuides = showGuides; + if (mPassword != null && mPassword.length() > 0) { + generatePasswordScore(); + } else { + mCurrentScore = 0; + } + + invalidate(); + requestLayout(); + } + + /** + * Determine whether the view is showing the guides for the password score + * + * @return True if the guides are being shown + */ + public boolean isShowingGuides() { + return mShowGuides; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java deleted file mode 100644 index 9e06c4cce..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014 Matt Allen - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.util.AttributeSet; - -/** - * Created by matt on 04/07/2014. - * https://github.com/matt-allen/android-password-strength-indicator - */ -public class PasswordStrengthBarView extends PasswordStrengthView { - - public PasswordStrengthBarView(Context context, AttributeSet attrs) { - super(context, attrs); - mMinHeight = 80; - mMinWidth = 300; - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - generateIndicatorColor(); - // Default to full width - int indWidth = mIndicatorWidth; - // If score, leave it as full - can cause it to become - // less than full width in this calculation - if (mCurrentScore < 20) indWidth = (mIndicatorWidth / 20) * mCurrentScore; - // Draw indicator - canvas.drawRect( - getPaddingLeft(), - getPaddingTop(), - indWidth, - mIndicatorHeight, - mIndicatorPaint - ); - // Draw guides if true - if (mShowGuides) { - // TODO: Try and do this with a loop, for efficiency - // Draw bottom guide border - float positionY = getHeight() - getPaddingBottom() - getPaddingTop(); - float notchHeight = (float) (positionY * 0.8); - canvas.drawLine( - getPaddingLeft(), - positionY, - getWidth() - getPaddingRight(), - positionY, - mGuidePaint); - // Show left-most notch - canvas.drawLine( - getPaddingLeft(), - positionY, - getPaddingLeft(), - notchHeight, - mGuidePaint - ); - // Show middle-left notch - canvas.drawLine( - (float) (mIndicatorWidth * 0.25) + getPaddingLeft(), - positionY, - (float) (mIndicatorWidth * 0.25) + getPaddingLeft(), - notchHeight, - mGuidePaint - ); - // Show the middle notch - canvas.drawLine( - (float) (mIndicatorWidth * 0.5) + getPaddingLeft(), - positionY, - (float) (mIndicatorWidth * 0.5) + getPaddingLeft(), - notchHeight, - mGuidePaint - ); - // Show the middle-right notch - canvas.drawLine( - (float) (mIndicatorWidth * 0.75) + getPaddingLeft(), - positionY, - (float) (mIndicatorWidth * 0.75) + getPaddingLeft(), - notchHeight, - mGuidePaint - ); - // Show the right-most notch - canvas.drawLine( - mIndicatorWidth + getPaddingLeft(), - positionY, - mIndicatorWidth + getPaddingLeft(), - notchHeight, - mGuidePaint - ); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java deleted file mode 100644 index bc5018497..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2014 Matt Allen - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.view.View; - -import org.sufficientlysecure.keychain.R; - -/** - * Created by Matt Allen - * 01/07/14 - * http://www.mattallensoftware.co.uk - * mattallen092@gmail.com - *

- * https://github.com/matt-allen/android-password-strength-indicator - *

- *

- * This View is designed to indicate how secure a user-entered password is in a visual way to - * relay to the user if they need to make it stronger. The strength of the password can be set - * at creation (or after) which will decide whether their password is strong enough. - *

- *

- *

- * The password strength is decided by an index of 20. The minimum score needed to pass is 10 - * which means the String has met the conditions imposed by the strength test, but can be improved. - * If the password scores 10-19 it is considered weak, and only if it scores 20 will it be - * considered strong. - *

- */ -public class PasswordStrengthView extends View { - - - protected int mMinWidth; - protected int mMinHeight; - - protected Paint mIndicatorPaint; - protected Paint mGuidePaint; - - protected int mIndicatorHeight; - protected int mIndicatorWidth; - protected int mCurrentScore; - - protected int mColorFail; - protected int mColorWeak; - protected int mColorStrong; - - protected boolean mShowGuides = true; - - /** - * Used to define that the indicator should only be looking - * for a weak password. The bare minimum is used here to let - * the user continue. - */ - public static final int STRENGTH_WEAK = 0; - - /** - * A fairly strict rule for generating a password. It encourages a password that is - * less easy to crack. - */ - public static final int STRENGTH_MEDIUM = 1; - - /** - * A strong algorithm that encourages very strong passwords that should be fairly long, with - * non-alphanumeric, numbers, and upper case. - */ - public static final int STRENGTH_STRONG = 2; - - private int mStrengthRequirement = -1; - protected String mPassword; - - public PasswordStrengthView(Context context, AttributeSet attrs) { - super(context, attrs); - - int COLOR_FAIL = context.getResources().getColor(R.color.android_red_light); - int COLOR_WEAK = context.getResources().getColor(R.color.android_orange_light); - int COLOR_STRONG = context.getResources().getColor(R.color.android_green_light); - - TypedArray style = context.getTheme().obtainStyledAttributes( - attrs, - R.styleable.PasswordStrengthView, - 0, 0); - - try { - mStrengthRequirement = style.getInteger(R.styleable.PasswordStrengthView_strength, - STRENGTH_MEDIUM); - mShowGuides = style.getBoolean(R.styleable.PasswordStrengthView_showGuides, true); - mColorFail = style.getColor(R.styleable.PasswordStrengthView_color_fail, COLOR_FAIL); - mColorWeak = style.getColor(R.styleable.PasswordStrengthView_color_weak, COLOR_WEAK); - mColorStrong = style.getColor(R.styleable.PasswordStrengthView_color_strong, - COLOR_STRONG); - } catch (Exception e) { - e.printStackTrace(); - } - // Create and style the paint used for drawing the guide on the indicator - mGuidePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mGuidePaint.setStyle(Paint.Style.FILL_AND_STROKE); - mGuidePaint.setColor(Color.BLACK); - // Create and style paint for indicator - mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mIndicatorPaint.setStyle(Paint.Style.FILL); - } - - /** - * This view can determine if the password entered by the user is acceptable for - * use by your use case. This is based on the strength requirement you have set. - * - * @return True if requirement has been met - */ - public boolean isStrengthRequirementMet() { - return (mCurrentScore >= 10); - } - - /** - * Change the strength requirement of the password entered by the user. This will also - * re-check the password already entered against these new requirements. - * - * @param requiredStrength Use the public constants of this class to set - */ - public void setStrengthRequirement(int requiredStrength) { - if (requiredStrength >= 0 && requiredStrength <= 2) { - mStrengthRequirement = requiredStrength; - if (mPassword != null && mPassword.length() > 0) { - generatePasswordScore(); - // Update view with new score - invalidate(); - requestLayout(); - } - } else { - throw new IndexOutOfBoundsException("Input out of expected range"); - } - } - - /** - * Update the password string to check strength of - * - * @param passwordString String representation of user-input - */ - public void setPassword(String passwordString) { - if (passwordString != null && passwordString.length() > 0) { - mPassword = passwordString; - generatePasswordScore(); - } else { - mPassword = ""; - mCurrentScore = 0; - } - - // Update view with new score - invalidate(); - requestLayout(); - } - - /** - * Private convenience method for adding to the password score - * - * @param score Amount to be added to current score - */ - protected void addToPasswordScore(int score) { - int newScore = mCurrentScore + score; - - // Limit max score - if (newScore > 20) { - mCurrentScore = 20; - } else { - mCurrentScore = newScore; - } - } - - /** - * Call this to determine the current strength requirement set on the algorithm - * - * @return Int representation of the current strength set for the indicator - */ - public int getStrengthRequirement() { - return mStrengthRequirement; - } - - /** - * Generate a score based on the password. The password will already need to be stored - * as a class member before running this. - */ - protected void generatePasswordScore() { - mCurrentScore = 0; - int upperCase = getUppercaseCount(mPassword); - int nonAlpha = getNonAlphanumericCount(mPassword); - int numbers = getNumberCount(mPassword); - switch (mStrengthRequirement) { - case STRENGTH_WEAK: - addToPasswordScore(mPassword.length() * 2); - addToPasswordScore(upperCase * 2); - addToPasswordScore(nonAlpha * 2); - addToPasswordScore(numbers * 2); - break; - - case STRENGTH_MEDIUM: - addToPasswordScore(mPassword.length()); - addToPasswordScore(upperCase); - addToPasswordScore(nonAlpha * 2); - addToPasswordScore(numbers); - break; - - case STRENGTH_STRONG: - addToPasswordScore(mPassword.length() / 2); - // Cut the score in half to make this a very high requirement - addToPasswordScore(upperCase); - addToPasswordScore(nonAlpha); - addToPasswordScore(numbers); - break; - } - } - - @Override - protected void onSizeChanged(int w, int h, int oldW, int oldH) { - super.onSizeChanged(w, h, oldW, oldH); - int paddingX = getPaddingLeft(); - int paddingY = getPaddingTop(); - mIndicatorHeight = h - paddingY; - mIndicatorWidth = w - paddingX; - } - - /** - * The standard parts of the onMeasure needed to create the password strength - * indicator. Subclasses should call super.onMeasure, but also need to set - * the minimum height and width in the constructor. - * - * @param widthMeasureSpec The measurement given by the system - * @param heightMeasureSpec The measurement given by the system - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // Set minimum space for the view to do it's thing - int minW = getPaddingLeft() + getPaddingRight() + mMinWidth; - int w = resolveSizeAndState(minW, widthMeasureSpec, 1); - // And give it enough height so it's visible - int minH = mMinHeight + getPaddingBottom() + getPaddingTop(); - int h = resolveSizeAndState(minH, heightMeasureSpec, 0); - // Feed these back into UIKit - setMeasuredDimension(w, h); - } - - /** - * Set the colour of the indicator {@code Paint} to one that is appropriate - * for the strength of the password. - */ - protected void generateIndicatorColor() { - int color = mColorFail; - if (mCurrentScore >= 18) { - color = mColorStrong; - } else if (mCurrentScore >= 10) { - color = mColorWeak; - } - mIndicatorPaint.setColor(color); - } - - /** - * Quick method to determine how many of the characters in a given string are upper case - * - * @param stringToCheck The string to examine - * @return Number of upper case characters - */ - protected int getUppercaseCount(String stringToCheck) { - int score = 0; - int loops = stringToCheck.length() - 1; - for (int i = 0; i <= loops; i++) { - if (Character.isUpperCase(stringToCheck.charAt(i))) { - score++; - } - } - return score; - } - - /** - * A convenience method to determine how many characters in the given String aren't - * letters or numbers. - * - * @param stringToCheck - * @return Number of characters that aren't numbers or letters - */ - protected int getNonAlphanumericCount(String stringToCheck) { - int score = 0; - int loops = stringToCheck.length() - 1; - for (int i = 0; i <= loops; i++) { - if (!Character.isLetter(stringToCheck.charAt(i)) && - !Character.isDigit(stringToCheck.charAt(i))) { - score++; - } - } - return score; - } - - /** - * A convenience method for returning the count of numbers in a given String. - * - * @param stringToCheck - * @return The numbers of digits in the String - */ - protected int getNumberCount(String stringToCheck) { - int score = 0; - int loops = stringToCheck.length() - 1; - for (int i = 0; i <= loops; i++) { - if (Character.isDigit(stringToCheck.charAt(i))) { - score++; - } - } - return score; - } - - /** - * Set the guides to show on the view.
- * On the line style, the guides will show underneath
- * On the rounded style, the guides will be shown on the outer edges.
- * The view will be redrawn after the method is called. - * - * @param showGuides True if you want the guides to be shown - */ - public void setShowGuides(boolean showGuides) { - mShowGuides = showGuides; - if (mPassword != null && mPassword.length() > 0) { - generatePasswordScore(); - } else { - mCurrentScore = 0; - } - - invalidate(); - requestLayout(); - } - - /** - * Determine whether the view is showing the guides for the password score - * - * @return True if the guides are being shown - */ - public boolean isShowingGuides() { - return mShowGuides; - } -} diff --git a/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml b/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml index 5f323716c..ffc5266b5 100644 --- a/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml +++ b/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml @@ -33,7 +33,7 @@ android:ems="10" android:layout_gravity="center_horizontal" /> - @color/primary_dark @color/accent - true + true false -- cgit v1.2.3 From c442d3bd0d3bac96614d3d5c0e833a42cab4706e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 26 Apr 2015 00:33:26 +0200 Subject: Put decrypt result in toolbar, some ui fixes for decrypt --- .../keychain/ui/DecryptFragment.java | 19 +-- .../keychain/ui/DecryptTextFragment.java | 6 +- .../drawable-hdpi/ic_content_copy_black_24dp.png | Bin 0 -> 284 bytes .../main/res/drawable-hdpi/ic_share_black_24dp.png | Bin 0 -> 499 bytes .../drawable-mdpi/ic_content_copy_black_24dp.png | Bin 0 -> 214 bytes .../main/res/drawable-mdpi/ic_share_black_24dp.png | Bin 0 -> 355 bytes .../drawable-xhdpi/ic_content_copy_black_24dp.png | Bin 0 -> 304 bytes .../res/drawable-xhdpi/ic_share_black_24dp.png | Bin 0 -> 614 bytes .../drawable-xxhdpi/ic_content_copy_black_24dp.png | Bin 0 -> 397 bytes .../res/drawable-xxhdpi/ic_share_black_24dp.png | Bin 0 -> 804 bytes .../ic_content_copy_black_24dp.png | Bin 0 -> 480 bytes .../res/drawable-xxxhdpi/ic_share_black_24dp.png | Bin 0 -> 1052 bytes .../src/main/res/layout/decrypt_text_activity.xml | 2 +- .../src/main/res/layout/decrypt_text_fragment.xml | 2 +- .../src/main/res/layout/toolbar_result_decrypt.xml | 145 +++++++++++++++++++++ OpenKeychain/src/main/res/menu/decrypt_menu.xml | 4 +- 16 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png create mode 100644 OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index d641f02f9..651b56ab0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -79,17 +79,18 @@ public abstract class DecryptFragment extends CryptoOperationFragment implements public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - mResultLayout = (LinearLayout) view.findViewById(R.id.result_main_layout); + // NOTE: These views are inside the activity! + mResultLayout = (LinearLayout) getActivity().findViewById(R.id.result_main_layout); mResultLayout.setVisibility(View.GONE); - mEncryptionIcon = (ImageView) view.findViewById(R.id.result_encryption_icon); - mEncryptionText = (TextView) view.findViewById(R.id.result_encryption_text); - mSignatureIcon = (ImageView) view.findViewById(R.id.result_signature_icon); - mSignatureText = (TextView) view.findViewById(R.id.result_signature_text); - mSignatureLayout = view.findViewById(R.id.result_signature_layout); - mSignatureName = (TextView) view.findViewById(R.id.result_signature_name); - mSignatureEmail = (TextView) view.findViewById(R.id.result_signature_email); - mSignatureAction = (TextView) view.findViewById(R.id.result_signature_action); + mEncryptionIcon = (ImageView) getActivity().findViewById(R.id.result_encryption_icon); + mEncryptionText = (TextView) getActivity().findViewById(R.id.result_encryption_text); + mSignatureIcon = (ImageView) getActivity().findViewById(R.id.result_signature_icon); + mSignatureText = (TextView) getActivity().findViewById(R.id.result_signature_text); + mSignatureLayout = getActivity().findViewById(R.id.result_signature_layout); + mSignatureName = (TextView) getActivity().findViewById(R.id.result_signature_name); + mSignatureEmail = (TextView) getActivity().findViewById(R.id.result_signature_email); + mSignatureAction = (TextView) getActivity().findViewById(R.id.result_signature_action); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 1b9ae917f..6f576a112 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -97,9 +97,9 @@ public class DecryptTextFragment extends DecryptFragment { /** * Create Intent Chooser but exclude decrypt activites */ - private Intent sendWithChooserExcludingEncrypt(String text) { + private Intent sendWithChooserExcludingDecrypt(String text) { Intent prototype = createSendIntent(text); - String title = getString(R.string.title_share_file); + String title = getString(R.string.title_share_message); // we don't want to decrypt the decrypted, no inception ;) String[] blacklist = new String[]{ @@ -147,7 +147,7 @@ public class DecryptTextFragment extends DecryptFragment { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.decrypt_share: { - startActivity(sendWithChooserExcludingEncrypt(mText.getText().toString())); + startActivity(sendWithChooserExcludingDecrypt(mText.getText().toString())); break; } case R.id.decrypt_copy: { diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.png new file mode 100644 index 000000000..dc8c85cce Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png new file mode 100644 index 000000000..2839b1352 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.png new file mode 100644 index 000000000..4ad9e552d Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png new file mode 100644 index 000000000..f0ff945b8 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.png new file mode 100644 index 000000000..c6f0e6b85 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png new file mode 100644 index 000000000..4b3675766 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.png new file mode 100644 index 000000000..081fbec5b Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png new file mode 100644 index 000000000..09d4df6af Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.png new file mode 100644 index 000000000..04c07fb56 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png new file mode 100644 index 000000000..0fe15fc05 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png differ diff --git a/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml b/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml index a6099e25e..41d7c5c95 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml @@ -5,7 +5,7 @@ + layout="@layout/toolbar_result_decrypt" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/res/menu/decrypt_menu.xml b/OpenKeychain/src/main/res/menu/decrypt_menu.xml index c0d7a519f..9e90fc9c7 100644 --- a/OpenKeychain/src/main/res/menu/decrypt_menu.xml +++ b/OpenKeychain/src/main/res/menu/decrypt_menu.xml @@ -5,13 +5,13 @@ \ No newline at end of file -- cgit v1.2.3