From 179f48a4dee1ac0f571b31024281bc7ca7d45cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 14 Sep 2014 00:11:23 +0200 Subject: First work on decrypt --- OpenKeychain/src/main/AndroidManifest.xml | 161 ++++++++++++++++++++ .../org/sufficientlysecure/keychain/Constants.java | 1 + .../keychain/ui/DecryptActivity.java | 166 --------------------- .../keychain/ui/DecryptOldActivity.java | 166 +++++++++++++++++++++ .../src/main/res/layout-large/decrypt_activity.xml | 18 --- .../main/res/layout-large/decrypt_activity_old.xml | 18 +++ .../src/main/res/layout/decrypt_activity.xml | 11 -- .../src/main/res/layout/decrypt_activity_old.xml | 11 ++ .../src/main/res/layout/decrypt_content.xml | 24 --- .../src/main/res/layout/decrypt_content_old.xml | 24 +++ 10 files changed, 381 insertions(+), 219 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOldActivity.java delete mode 100644 OpenKeychain/src/main/res/layout-large/decrypt_activity.xml create mode 100644 OpenKeychain/src/main/res/layout-large/decrypt_activity_old.xml delete mode 100644 OpenKeychain/src/main/res/layout/decrypt_activity.xml create mode 100644 OpenKeychain/src/main/res/layout/decrypt_activity_old.xml delete mode 100644 OpenKeychain/src/main/res/layout/decrypt_content.xml create mode 100644 OpenKeychain/src/main/res/layout/decrypt_content_old.xml diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index a83992d09..63ffc8acd 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -195,6 +195,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - * Copyright (C) 2010-2014 Thialfihar - * - * 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; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.view.PagerTabStrip; -import android.support.v4.view.ViewPager; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.api.OpenKeychainIntents; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.regex.Matcher; - -public class DecryptActivity extends DrawerActivity { - - /* Intents */ - public static final String ACTION_DECRYPT = OpenKeychainIntents.DECRYPT; - - /* EXTRA keys for input */ - public static final String EXTRA_TEXT = OpenKeychainIntents.DECRYPT_EXTRA_TEXT; - - ViewPager mViewPager; - PagerTabStrip mPagerTabStrip; - PagerTabStripAdapter mTabsAdapter; - - Bundle mMessageFragmentBundle = new Bundle(); - Bundle mFileFragmentBundle = new Bundle(); - int mSwitchToTab = PAGER_TAB_MESSAGE; - - private static final int PAGER_TAB_MESSAGE = 0; - private static final int PAGER_TAB_FILE = 1; - - private void initView() { - mViewPager = (ViewPager) findViewById(R.id.decrypt_pager); - mPagerTabStrip = (PagerTabStrip) findViewById(R.id.decrypt_pager_tab_strip); - - mTabsAdapter = new PagerTabStripAdapter(this); - mViewPager.setAdapter(mTabsAdapter); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.decrypt_activity); - - initView(); - - activateDrawerNavigation(savedInstanceState); - - // Handle intent actions, maybe changes the bundles - handleActions(getIntent()); - - mTabsAdapter.addTab(DecryptMessageFragment.class, - mMessageFragmentBundle, getString(R.string.label_message)); - mTabsAdapter.addTab(DecryptFileFragment.class, - mFileFragmentBundle, getString(R.string.label_file)); - mViewPager.setCurrentItem(mSwitchToTab); - } - - - /** - * Handles all actions with this intent - * - * @param intent - */ - private void handleActions(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - String type = intent.getType(); - Uri uri = intent.getData(); - - if (extras == null) { - extras = new Bundle(); - } - - /* - * Android's Action - */ - if (Intent.ACTION_SEND.equals(action) && type != null) { - // When sending to Keychain Decrypt via share menu - if ("text/plain".equals(type)) { - // Plain text - String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); - if (sharedText != null) { - // handle like normal text decryption, override action and extras to later - // executeServiceMethod ACTION_DECRYPT in main actions - extras.putString(EXTRA_TEXT, sharedText); - action = ACTION_DECRYPT; - } - } else { - // Binary via content provider (could also be files) - // override uri to get stream from send - uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); - action = ACTION_DECRYPT; - } - } else if (Intent.ACTION_VIEW.equals(action)) { - // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) - - // override action - action = ACTION_DECRYPT; - mFileFragmentBundle.putBoolean(DecryptFileFragment.ARG_FROM_VIEW_INTENT, true); - } - - String textData = extras.getString(EXTRA_TEXT); - - /** - * Main Actions - */ - if (ACTION_DECRYPT.equals(action) && textData != null) { - Log.d(Constants.TAG, "textData not null, matching text ..."); - Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(textData); - if (matcher.matches()) { - Log.d(Constants.TAG, "PGP_MESSAGE matched"); - textData = matcher.group(1); - // replace non breakable spaces - textData = textData.replaceAll("\\xa0", " "); - - mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); - mSwitchToTab = PAGER_TAB_MESSAGE; - } else { - matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(textData); - if (matcher.matches()) { - Log.d(Constants.TAG, "PGP_CLEARTEXT_SIGNATURE matched"); - textData = matcher.group(1); - // replace non breakable spaces - textData = textData.replaceAll("\\xa0", " "); - - mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); - mSwitchToTab = PAGER_TAB_MESSAGE; - } else { - Log.d(Constants.TAG, "Nothing matched!"); - } - } - } else if (ACTION_DECRYPT.equals(action) && uri != null) { - mFileFragmentBundle.putParcelable(DecryptFileFragment.ARG_URI, uri); - mSwitchToTab = PAGER_TAB_FILE; - } else if (ACTION_DECRYPT.equals(action)) { - Log.e(Constants.TAG, - "Include the extra 'text' or an Uri with setData() in your Intent!"); - } - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOldActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOldActivity.java new file mode 100644 index 000000000..f6dfed5d7 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOldActivity.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2010-2014 Thialfihar + * + * 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; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.view.PagerTabStrip; +import android.support.v4.view.ViewPager; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.api.OpenKeychainIntents; +import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.regex.Matcher; + +public class DecryptOldActivity extends DrawerActivity { + + /* Intents */ + public static final String ACTION_DECRYPT = OpenKeychainIntents.DECRYPT; + + /* EXTRA keys for input */ + public static final String EXTRA_TEXT = OpenKeychainIntents.DECRYPT_EXTRA_TEXT; + + ViewPager mViewPager; + PagerTabStrip mPagerTabStrip; + PagerTabStripAdapter mTabsAdapter; + + Bundle mMessageFragmentBundle = new Bundle(); + Bundle mFileFragmentBundle = new Bundle(); + int mSwitchToTab = PAGER_TAB_MESSAGE; + + private static final int PAGER_TAB_MESSAGE = 0; + private static final int PAGER_TAB_FILE = 1; + + private void initView() { + mViewPager = (ViewPager) findViewById(R.id.decrypt_pager); + mPagerTabStrip = (PagerTabStrip) findViewById(R.id.decrypt_pager_tab_strip); + + mTabsAdapter = new PagerTabStripAdapter(this); + mViewPager.setAdapter(mTabsAdapter); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.decrypt_activity_old); + + initView(); + + activateDrawerNavigation(savedInstanceState); + + // Handle intent actions, maybe changes the bundles + handleActions(getIntent()); + + mTabsAdapter.addTab(DecryptMessageFragment.class, + mMessageFragmentBundle, getString(R.string.label_message)); + mTabsAdapter.addTab(DecryptFileFragment.class, + mFileFragmentBundle, getString(R.string.label_file)); + mViewPager.setCurrentItem(mSwitchToTab); + } + + + /** + * Handles all actions with this intent + * + * @param intent + */ + private void handleActions(Intent intent) { + String action = intent.getAction(); + Bundle extras = intent.getExtras(); + String type = intent.getType(); + Uri uri = intent.getData(); + + if (extras == null) { + extras = new Bundle(); + } + + /* + * Android's Action + */ + if (Intent.ACTION_SEND.equals(action) && type != null) { + // When sending to Keychain Decrypt via share menu + if ("text/plain".equals(type)) { + // Plain text + String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); + if (sharedText != null) { + // handle like normal text decryption, override action and extras to later + // executeServiceMethod ACTION_DECRYPT in main actions + extras.putString(EXTRA_TEXT, sharedText); + action = ACTION_DECRYPT; + } + } else { + // Binary via content provider (could also be files) + // override uri to get stream from send + uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); + action = ACTION_DECRYPT; + } + } else if (Intent.ACTION_VIEW.equals(action)) { + // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) + + // override action + action = ACTION_DECRYPT; + mFileFragmentBundle.putBoolean(DecryptFileFragment.ARG_FROM_VIEW_INTENT, true); + } + + String textData = extras.getString(EXTRA_TEXT); + + /** + * Main Actions + */ + if (ACTION_DECRYPT.equals(action) && textData != null) { + Log.d(Constants.TAG, "textData not null, matching text ..."); + Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(textData); + if (matcher.matches()) { + Log.d(Constants.TAG, "PGP_MESSAGE matched"); + textData = matcher.group(1); + // replace non breakable spaces + textData = textData.replaceAll("\\xa0", " "); + + mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); + mSwitchToTab = PAGER_TAB_MESSAGE; + } else { + matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(textData); + if (matcher.matches()) { + Log.d(Constants.TAG, "PGP_CLEARTEXT_SIGNATURE matched"); + textData = matcher.group(1); + // replace non breakable spaces + textData = textData.replaceAll("\\xa0", " "); + + mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); + mSwitchToTab = PAGER_TAB_MESSAGE; + } else { + Log.d(Constants.TAG, "Nothing matched!"); + } + } + } else if (ACTION_DECRYPT.equals(action) && uri != null) { + mFileFragmentBundle.putParcelable(DecryptFileFragment.ARG_URI, uri); + mSwitchToTab = PAGER_TAB_FILE; + } else if (ACTION_DECRYPT.equals(action)) { + Log.e(Constants.TAG, + "Include the extra 'text' or an Uri with setData() in your Intent!"); + } + } + +} diff --git a/OpenKeychain/src/main/res/layout-large/decrypt_activity.xml b/OpenKeychain/src/main/res/layout-large/decrypt_activity.xml deleted file mode 100644 index 06487a982..000000000 --- a/OpenKeychain/src/main/res/layout-large/decrypt_activity.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout-large/decrypt_activity_old.xml b/OpenKeychain/src/main/res/layout-large/decrypt_activity_old.xml new file mode 100644 index 000000000..fb1aaa1e8 --- /dev/null +++ b/OpenKeychain/src/main/res/layout-large/decrypt_activity_old.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/decrypt_activity.xml b/OpenKeychain/src/main/res/layout/decrypt_activity.xml deleted file mode 100644 index bb0e463b3..000000000 --- a/OpenKeychain/src/main/res/layout/decrypt_activity.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/OpenKeychain/src/main/res/layout/decrypt_activity_old.xml b/OpenKeychain/src/main/res/layout/decrypt_activity_old.xml new file mode 100644 index 000000000..15216af32 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/decrypt_activity_old.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/OpenKeychain/src/main/res/layout/decrypt_content.xml b/OpenKeychain/src/main/res/layout/decrypt_content.xml deleted file mode 100644 index f62cf615c..000000000 --- a/OpenKeychain/src/main/res/layout/decrypt_content.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/decrypt_content_old.xml b/OpenKeychain/src/main/res/layout/decrypt_content_old.xml new file mode 100644 index 000000000..f62cf615c --- /dev/null +++ b/OpenKeychain/src/main/res/layout/decrypt_content_old.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3 From 1c32d1df8801968ea6423ee4f1a9160e0c4ff0c3 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Fri, 12 Sep 2014 08:34:51 -0700 Subject: Add cloud search tab, lose Keybase/Keyserver tabs, re-organize prefs --- .../org/sufficientlysecure/keychain/Constants.java | 2 + .../keychain/helper/EmailKeyHelper.java | 6 +- .../keychain/helper/Preferences.java | 32 ++++ .../keychain/keyimport/CloudSearch.java | 90 ++++++++++ .../keychain/keyimport/ImportKeysList.java | 84 +++++++++ .../keychain/keyimport/ImportKeysListEntry.java | 7 + .../keychain/keyimport/Keyserver.java | 16 +- .../keychain/ui/CreateKeyFinalFragment.java | 2 +- .../keychain/ui/ImportKeysActivity.java | 89 +++------- .../keychain/ui/ImportKeysCloudFragment.java | 160 +++++++++++++++++ .../keychain/ui/ImportKeysKeybaseFragment.java | 122 ------------- .../keychain/ui/ImportKeysListFragment.java | 66 ++----- .../keychain/ui/ImportKeysServerFragment.java | 197 --------------------- .../keychain/ui/PreferencesActivity.java | 88 ++++++--- .../keychain/ui/PreferencesKeyServerActivity.java | 34 ++++ .../ui/adapter/ImportKeysListCloudLoader.java | 122 +++++++++++++ .../ui/adapter/ImportKeysListKeybaseLoader.java | 103 ----------- .../ui/adapter/ImportKeysListServerLoader.java | 125 ------------- .../src/main/res/drawable/button_rounded_blue.xml | 37 ++++ .../main/res/layout/import_keys_cloud_fragment.xml | 57 ++++++ .../res/layout/import_keys_keybase_fragment.xml | 32 ---- .../src/main/res/layout/import_keys_list_entry.xml | 2 + .../res/layout/import_keys_server_fragment.xml | 76 -------- .../src/main/res/layout/key_server_preference.xml | 25 ++- OpenKeychain/src/main/res/values/strings.xml | 8 +- OpenKeychain/src/main/res/xml/adv_preferences.xml | 13 +- .../src/main/res/xml/cloud_search_prefs.xml | 20 +++ OpenKeychain/src/main/res/xml/gen_preferences.xml | 15 -- .../src/main/res/xml/preference_headers.xml | 4 +- 29 files changed, 804 insertions(+), 830 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java create mode 100644 OpenKeychain/src/main/res/drawable/button_rounded_blue.xml create mode 100644 OpenKeychain/src/main/res/layout/import_keys_cloud_fragment.xml delete mode 100644 OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml delete mode 100644 OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml create mode 100644 OpenKeychain/src/main/res/xml/cloud_search_prefs.xml delete mode 100644 OpenKeychain/src/main/res/xml/gen_preferences.xml diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index db78a36c1..8ee769fdf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -81,6 +81,8 @@ public final class Constants { public static final String CACHED_CONSOLIDATE = "cachedConsolidate"; public static final String CACHED_CONSOLIDATE_SECRETS = "cachedConsolidateSecrets"; public static final String CACHED_CONSOLIDATE_PUBLICS = "cachedConsolidatePublics"; + public static final String SEARCH_KEYSERVER = "search_keyserver_pref"; + public static final String SEARCH_KEYBASE = "search_keybase_pref"; public static final String USE_DEFAULT_YUBIKEY_PIN = "useDefaultYubikeyPin"; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/EmailKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/EmailKeyHelper.java index d8efdc480..91325ca1f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/EmailKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/EmailKeyHelper.java @@ -61,9 +61,9 @@ public class EmailKeyHelper { if (keys.isEmpty()) { // Most users don't have the SRV record, so ask a default server as well - String[] servers = Preferences.getPreferences(context).getKeyServers(); - if (servers != null && servers.length != 0) { - HkpKeyserver hkp = new HkpKeyserver(servers[0]); + String server = Preferences.getPreferences(context).getPreferredKeyserver(); + if (server != null) { + HkpKeyserver hkp = new HkpKeyserver(server); keys.addAll(getEmailKeys(mail, hkp)); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java index aa4621893..bf09997a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java @@ -220,6 +220,9 @@ public class Preferences { } return servers.toArray(chunks); } + public String getPreferredKeyserver() { + return getKeyServers()[0]; + } public void setKeyServers(String[] value) { SharedPreferences.Editor editor = mSharedPreferences.edit(); @@ -248,6 +251,35 @@ public class Preferences { return mSharedPreferences.getBoolean(Constants.Pref.WRITE_VERSION_HEADER, false); } + public void setSearchKeyserver(boolean searchKeyserver) { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(Pref.SEARCH_KEYSERVER, searchKeyserver); + editor.commit(); + } + public void setSearchKeybase(boolean searchKeybase) { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(Pref.SEARCH_KEYBASE, searchKeybase); + editor.commit(); + } + + public CloudSearchPrefs getCloudSearchPrefs() { + return new CloudSearchPrefs(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true), + mSharedPreferences.getBoolean(Pref.SEARCH_KEYBASE, true), + getPreferredKeyserver()); + } + + public static class CloudSearchPrefs { + public final boolean searchKeyserver; + public final boolean searchKeybase; + public final String keyserver; + + public CloudSearchPrefs(boolean searchKeyserver, boolean searchKeybase, String keyserver) { + this.searchKeyserver = searchKeyserver; + this.searchKeybase = searchKeybase; + this.keyserver = keyserver; + } + } + public void updatePreferences() { if (mSharedPreferences.getInt(Constants.Pref.PREF_DEFAULT_VERSION, 0) != Constants.Defaults.PREF_VERSION) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java new file mode 100644 index 000000000..27d826c59 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Tim Bray + * + * 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.keyimport; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.ArrayList; +import java.util.Vector; + +/** + * Search two or more types of server for online keys. + */ +public class CloudSearch { + + private final static long SECONDS = 1000; + + public static ArrayList search(final String query, Preferences.CloudSearchPrefs cloudPrefs) + throws Keyserver.CloudSearchFailureException { + final ArrayList servers = new ArrayList(); + + // it's a Vector for sync, multiple threads might report problems + final Vector problems = new Vector(); + + if (cloudPrefs.searchKeyserver) { + servers.add(new HkpKeyserver(cloudPrefs.keyserver)); + } + if (cloudPrefs.searchKeybase) { + servers.add(new KeybaseKeyserver()); + } + final ImportKeysList results = new ImportKeysList(servers.size()); + + for (final Keyserver keyserver : servers) { + Runnable r = new Runnable() { + @Override + public void run() { + try { + results.addAll(keyserver.search(query)); + } catch (Keyserver.CloudSearchFailureException e) { + problems.add(e); + } + results.finishedAdding(); // notifies if all searchers done + } + }; + new Thread(r).start(); + } + + // wait for either all the searches to come back, or 10 seconds + synchronized(results) { + try { + results.wait(10 * SECONDS); + } catch (InterruptedException e) { + } + } + + if (results.outstandingSuppliers() > 0) { + String message = "Launched " + servers.size() + " cloud searchers, but" + + results.outstandingSuppliers() + "failed to complete."; + problems.add(new Keyserver.QueryFailedException(message)); + } + + if (!problems.isEmpty()) { + for (Keyserver.CloudSearchFailureException e : problems) { + Log.d(Constants.TAG, "Cloud search exception: " + e.getLocalizedMessage()); + } + + // only throw exception if we didn’t get any results + if (results.isEmpty()) { + throw problems.get(0); + } + } + + return results; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java new file mode 100644 index 000000000..15de8cb8f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014 Tim Bray + * + * 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.keyimport; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Just an ArrayList, only with a synchronized dupe-merging add/addAll, and a sign-off method + */ +public class ImportKeysList extends ArrayList { + + private int mSupplierCount; + + public ImportKeysList(int supplierCount) { + mSupplierCount = supplierCount; + } + + @Override + public boolean add(ImportKeysListEntry toAdd) { + addOrMerge(toAdd); + return true; // that’s what the ArrayList#add contract says + } + + @Override + public boolean addAll(Collection addThese) { + boolean modified = false; + for (ImportKeysListEntry toAdd : addThese) { + modified = addOrMerge(toAdd) || modified; + } + return modified; + } + + // NOTE: side-effects + // NOTE: synchronized + private synchronized boolean addOrMerge(ImportKeysListEntry toAdd) { + for (ImportKeysListEntry existing : this) { + if (toAdd.hasSameKeyAs(existing)) { + return mergeIDs(toAdd, existing); + } + } + return super.add(toAdd); + } + + // being a little anal about the ArrayList#addAll contract here + private boolean mergeIDs(ImportKeysListEntry incoming, ImportKeysListEntry existing) { + boolean modified = false; + ArrayList incomingIDs = incoming.getUserIds(); + ArrayList existingIDs = existing.getUserIds(); + for (String incomingID : incomingIDs) { + if (!existingIDs.contains(incomingID)) { + existingIDs.add(incomingID); + modified = true; + } + } + return modified; + } + + // NOTE: synchronized + public synchronized void finishedAdding() { + mSupplierCount--; + if (mSupplierCount == 0) { + this.notify(); + } + } + + public int outstandingSuppliers() { + return mSupplierCount; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java index da70f1505..c10cd2e70 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -107,6 +107,13 @@ public class ImportKeysListEntry implements Serializable, Parcelable { return super.hashCode(); } + public boolean hasSameKeyAs(Object o) { + if (mFingerprintHex == null || o == null || !(o instanceof ImportKeysListEntry)) { + return false; + } + return mFingerprintHex.equals(((ImportKeysListEntry) o).mFingerprintHex); + } + public String getKeyIdHex() { return mKeyIdHex; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java index b726529f8..5e4bd0b70 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java @@ -24,7 +24,19 @@ import java.io.InputStream; import java.util.List; public abstract class Keyserver { - public static class QueryFailedException extends Exception { + + public static class CloudSearchFailureException extends Exception { + private static final long serialVersionUID = 2703768928624654515L; + + public CloudSearchFailureException(String message) { + super(message); + } + public CloudSearchFailureException() { + super(); + } + } + + public static class QueryFailedException extends CloudSearchFailureException { private static final long serialVersionUID = 2703768928624654512L; public QueryFailedException(String message) { @@ -32,7 +44,7 @@ public abstract class Keyserver { } } - public static class QueryNeedsRepairException extends Exception { + public static class QueryNeedsRepairException extends CloudSearchFailureException { private static final long serialVersionUID = 2693768928624654512L; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index dc9fa78e5..c6edc47a1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -204,7 +204,7 @@ public class CreateKeyFinalFragment extends Fragment { Bundle data = new Bundle(); // upload to favorite keyserver - String keyserver = Preferences.getPreferences(getActivity()).getKeyServers()[0]; + String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver(); data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, keyserver); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); 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 d644dabc2..518a8046a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -68,8 +68,6 @@ public class ImportKeysActivity extends ActionBarActivity { + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN"; public static final String ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_FILE_AND_RETURN"; - public static final String ACTION_IMPORT_KEY_FROM_KEYBASE = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_KEYBASE"; // Actions for internal use only: public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX @@ -101,12 +99,11 @@ public class ImportKeysActivity extends ActionBarActivity { public static final int VIEW_PAGER_HEIGHT = 64; // dp private static final int ALL_TABS = -1; - private static final int TAB_KEYSERVER = 0; + private static final int TAB_CLOUD = 0; private static final int TAB_QR_CODE = 1; private static final int TAB_FILE = 2; - private static final int TAB_KEYBASE = 3; - private int mSwitchToTab = TAB_KEYSERVER; + private int mSwitchToTab = TAB_CLOUD; @Override protected void onCreate(Bundle savedInstanceState) { @@ -193,8 +190,8 @@ public class ImportKeysActivity extends ActionBarActivity { if (query != null && query.length() > 0) { // display keyserver fragment with query serverBundle = new Bundle(); - serverBundle.putString(ImportKeysServerFragment.ARG_QUERY, query); - mSwitchToTab = TAB_KEYSERVER; + serverBundle.putString(ImportKeysCloudFragment.ARG_QUERY, query); + mSwitchToTab = TAB_CLOUD; // action: search immediately startListFragment(savedInstanceState, null, null, query); @@ -214,11 +211,11 @@ public class ImportKeysActivity extends ActionBarActivity { // display keyserver fragment with query serverBundle = new Bundle(); - serverBundle.putString(ImportKeysServerFragment.ARG_QUERY, query); - serverBundle.putBoolean(ImportKeysServerFragment.ARG_DISABLE_QUERY_EDIT, true); + serverBundle.putString(ImportKeysCloudFragment.ARG_QUERY, query); + serverBundle.putBoolean(ImportKeysCloudFragment.ARG_DISABLE_QUERY_EDIT, true); // display server tab only - showTabOnly = TAB_KEYSERVER; - mSwitchToTab = TAB_KEYSERVER; + showTabOnly = TAB_CLOUD; + mSwitchToTab = TAB_CLOUD; // action: search immediately startListFragment(savedInstanceState, null, null, query); @@ -257,12 +254,6 @@ public class ImportKeysActivity extends ActionBarActivity { // NOTE: this only displays the appropriate fragment, no actions are taken mSwitchToTab = TAB_QR_CODE; - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else if (ACTION_IMPORT_KEY_FROM_KEYBASE.equals(action)) { - // NOTE: this only displays the appropriate fragment, no actions are taken - mSwitchToTab = TAB_KEYBASE; - // no immediate actions! startListFragment(savedInstanceState, null, null, null); } else { @@ -299,19 +290,17 @@ public class ImportKeysActivity extends ActionBarActivity { switch (showTabOnly) { case ALL_TABS: - // show all tabs - mTabsAdapter.addTab(ImportKeysServerFragment.class, - serverBundle, getString(R.string.import_tab_keyserver)); + // show default tabs + mTabsAdapter.addTab(ImportKeysCloudFragment.class, + serverBundle, getString(R.string.import_tab_cloud)); mTabsAdapter.addTab(ImportKeysQrCodeFragment.class, null, getString(R.string.import_tab_qr_code)); mTabsAdapter.addTab(ImportKeysFileFragment.class, null, getString(R.string.import_tab_direct)); - mTabsAdapter.addTab(ImportKeysKeybaseFragment.class, - null, getString(R.string.import_tab_keybase)); break; - case TAB_KEYSERVER: - mTabsAdapter.addTab(ImportKeysServerFragment.class, - serverBundle, getString(R.string.import_tab_keyserver)); + case TAB_CLOUD: + mTabsAdapter.addTab(ImportKeysCloudFragment.class, + serverBundle, getString(R.string.import_tab_cloud)); break; case TAB_QR_CODE: mTabsAdapter.addTab(ImportKeysQrCodeFragment.class, @@ -321,10 +310,6 @@ public class ImportKeysActivity extends ActionBarActivity { mTabsAdapter.addTab(ImportKeysFileFragment.class, null, getString(R.string.import_tab_direct)); break; - case TAB_KEYBASE: - mTabsAdapter.addTab(ImportKeysKeybaseFragment.class, - null, getString(R.string.import_tab_keybase)); - break; } // update layout after operations @@ -380,18 +365,17 @@ public class ImportKeysActivity extends ActionBarActivity { if (mViewPager.getAdapter() != null) mViewPager.setAdapter(null); mViewPager.setAdapter(mTabsAdapter); - mViewPager.setCurrentItem(TAB_KEYSERVER); + mViewPager.setCurrentItem(TAB_CLOUD); - ImportKeysServerFragment f = (ImportKeysServerFragment) - getActiveFragment(mViewPager, TAB_KEYSERVER); + ImportKeysCloudFragment f = (ImportKeysCloudFragment) + getActiveFragment(mViewPager, TAB_CLOUD); - // ask favorite keyserver - String keyserver = Preferences.getPreferences(ImportKeysActivity.this).getKeyServers()[0]; + // search config + Preferences prefs = Preferences.getPreferences(ImportKeysActivity.this); + Preferences.CloudSearchPrefs cloudPrefs = new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); - // set fields of ImportKeysServerFragment - f.setQueryAndKeyserver(query, keyserver); // search directly - loadCallback(new ImportKeysListFragment.KeyserverLoaderState(query, keyserver)); + loadCallback(new ImportKeysListFragment.CloudLoaderState(query, cloudPrefs)); } // http://stackoverflow.com/a/9293207 @@ -522,8 +506,8 @@ public class ImportKeysActivity extends ActionBarActivity { Log.e(Constants.TAG, "Problem writing cache file", e); Notify.showNotify(this, "Problem writing cache file!", Notify.Style.ERROR); } - } else if (ls instanceof ImportKeysListFragment.KeyserverLoaderState) { - ImportKeysListFragment.KeyserverLoaderState sls = (ImportKeysListFragment.KeyserverLoaderState) ls; + } else if (ls instanceof ImportKeysListFragment.CloudLoaderState) { + ImportKeysListFragment.CloudLoaderState sls = (ImportKeysListFragment.CloudLoaderState) ls; // Send all information needed to service to query keys in other thread Intent intent = new Intent(this, KeychainIntentService.class); @@ -533,31 +517,7 @@ public class ImportKeysActivity extends ActionBarActivity { // fill values for this action Bundle data = new Bundle(); - data.putString(KeychainIntentService.DOWNLOAD_KEY_SERVER, sls.keyserver); - - // get selected key entries - ArrayList selectedEntries = mListFragment.getSelectedEntries(); - data.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, selectedEntries); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } else if (ls instanceof ImportKeysListFragment.KeybaseLoaderState) { - // Send all information needed to service to query keys in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYBASE_KEYS); - - // fill values for this action - Bundle data = new Bundle(); + data.putString(KeychainIntentService.DOWNLOAD_KEY_SERVER, sls.mCloudPrefs.keyserver); // get selected key entries ArrayList selectedEntries = mListFragment.getSelectedEntries(); @@ -574,7 +534,6 @@ public class ImportKeysActivity extends ActionBarActivity { // start service with intent startService(intent); - } else { Notify.showNotify(this, R.string.error_nothing_import, Notify.Style.ERROR); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java new file mode 100644 index 000000000..6b4b833c6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2013-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; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ContactHelper; +import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.util.Log; + +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"; + + private ImportKeysActivity mImportActivity; + + private View mSearchButton; + private AutoCompleteTextView mQueryEditText; + private View mConfigButton; + private ArrayAdapter mServerAdapter; + + /** + * Creates new instance of this fragment + */ + public static ImportKeysCloudFragment newInstance(String query, String keyserver, boolean doKeyserver, boolean doKeybase) { + ImportKeysCloudFragment frag = new ImportKeysCloudFragment(); + + Bundle args = new Bundle(); + args.putString(ARG_QUERY, query); + + frag.setArguments(args); + + return frag; + } + + /** + * Inflate the layout for this fragment + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.import_keys_cloud_fragment, container, false); + + mSearchButton = view.findViewById(R.id.cloud_import_server_search); + mQueryEditText = (AutoCompleteTextView) view.findViewById(R.id.cloud_import_server_query); + mConfigButton = view.findViewById(R.id.cloud_import_server_config_button); + + List namesAndEmails = ContactHelper.getContactNames(getActivity()); + namesAndEmails.addAll(ContactHelper.getContactMails(getActivity())); + mQueryEditText.setThreshold(3); + mQueryEditText.setAdapter( + new ArrayAdapter + (getActivity(), android.R.layout.simple_spinner_dropdown_item, + namesAndEmails + ) + ); + + mSearchButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + search(mQueryEditText.getText().toString()); + + // close keyboard after pressing search + InputMethodManager imm = + (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0); + } + }); + + mQueryEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEARCH) { + search(mQueryEditText.getText().toString()); + + // Don't return true to let the keyboard close itself after pressing search + return false; + } + return false; + } + }); + + mConfigButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(mImportActivity, PreferencesActivity.class); + // GRR, for some reason I can’t set the Action or I get an incomprehensible + // exception about “modern two-pane layouts” + // i.setAction(PreferencesActivity.ACTION_PREFS_CLOUD); + startActivity(i); + } + }); + + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // set displayed values + if (getArguments() != null) { + if (getArguments().containsKey(ARG_QUERY)) { + String query = getArguments().getString(ARG_QUERY); + mQueryEditText.setText(query, TextView.BufferType.EDITABLE); + + Log.d(Constants.TAG, "query: " + query); + } + + if (getArguments().getBoolean(ARG_DISABLE_QUERY_EDIT, false)) { + mQueryEditText.setEnabled(false); + } + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + mImportActivity = (ImportKeysActivity) activity; + } + + private void search(String query) { + Preferences prefs = Preferences.getPreferences(getActivity()); + mImportActivity.loadCallback(new ImportKeysListFragment.CloudLoaderState(query, prefs.getCloudSearchPrefs())); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java deleted file mode 100644 index 3a82bdc32..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysKeybaseFragment.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 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; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; - -/** - * Import public keys from the Keybase.io directory. First cut: just raw search. - * TODO: make a pick list of the people you’re following on keybase - */ -public class ImportKeysKeybaseFragment extends Fragment { - - private ImportKeysActivity mImportActivity; - private View mSearchButton; - private EditText mQueryEditText; - - public static final String ARG_QUERY = "query"; - - /** - * Creates new instance of this fragment - */ - public static ImportKeysKeybaseFragment newInstance() { - ImportKeysKeybaseFragment frag = new ImportKeysKeybaseFragment(); - - Bundle args = new Bundle(); - frag.setArguments(args); - - return frag; - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_keybase_fragment, container, false); - - mQueryEditText = (EditText) view.findViewById(R.id.import_keybase_query); - - mSearchButton = view.findViewById(R.id.import_keybase_search); - mSearchButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - String query = mQueryEditText.getText().toString(); - search(query); - - // close keyboard after pressing search - InputMethodManager imm = - (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0); - } - }); - - mQueryEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_SEARCH) { - String query = mQueryEditText.getText().toString(); - search(query); - - // Don't return true to let the keyboard close itself after pressing search - return false; - } - return false; - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - // set displayed values - if (getArguments() != null) { - if (getArguments().containsKey(ARG_QUERY)) { - String query = getArguments().getString(ARG_QUERY); - mQueryEditText.setText(query, TextView.BufferType.EDITABLE); - } - } - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - mImportActivity = (ImportKeysActivity) activity; - } - - private void search(String query) { - mImportActivity.loadCallback(new ImportKeysListFragment.KeybaseLoaderState(query)); - } -} 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 fde0f5f23..f1f234461 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -37,9 +37,8 @@ import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListKeybaseLoader; +import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListCloudLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Notify; @@ -63,8 +62,7 @@ public class ImportKeysListFragment extends ListFragment implements private LoaderState mLoaderState; private static final int LOADER_ID_BYTES = 0; - private static final int LOADER_ID_SERVER_QUERY = 1; - private static final int LOADER_ID_KEYBASE = 2; + private static final int LOADER_ID_CLOUD = 1; private LongSparseArray mCachedKeyData; @@ -118,21 +116,13 @@ public class ImportKeysListFragment extends ListFragment implements } } - static public class KeyserverLoaderState extends LoaderState { - String serverQuery; - String keyserver; + static public class CloudLoaderState extends LoaderState { + Preferences.CloudSearchPrefs mCloudPrefs; + String mServerQuery; - KeyserverLoaderState(String serverQuery, String keyserver) { - this.serverQuery = serverQuery; - this.keyserver = keyserver; - } - } - - static public class KeybaseLoaderState extends LoaderState { - String keybaseQuery; - - KeybaseLoaderState(String keybaseQuery) { - this.keybaseQuery = keybaseQuery; + CloudLoaderState(String serverQuery, Preferences.CloudSearchPrefs cloudPrefs) { + mServerQuery = serverQuery; + mCloudPrefs = cloudPrefs; } } @@ -161,9 +151,8 @@ public class ImportKeysListFragment extends ListFragment implements } else if (query != null) { // TODO: this is used when updating a key. // Currently it simply uses keyserver nr 0 - String keyserver = Preferences.getPreferences(getActivity()) - .getKeyServers()[0]; - mLoaderState = new KeyserverLoaderState(query, keyserver); + Preferences prefs = Preferences.getPreferences(getActivity()); + mLoaderState = new CloudLoaderState(query, prefs.getCloudSearchPrefs()); } getListView().setOnTouchListener(new OnTouchListener() { @@ -202,11 +191,8 @@ public class ImportKeysListFragment extends ListFragment implements if (getLoaderManager().getLoader(LOADER_ID_BYTES) != null) { getLoaderManager().destroyLoader(LOADER_ID_BYTES); } - if (getLoaderManager().getLoader(LOADER_ID_SERVER_QUERY) != null) { - getLoaderManager().destroyLoader(LOADER_ID_SERVER_QUERY); - } - if (getLoaderManager().getLoader(LOADER_ID_KEYBASE) != null) { - getLoaderManager().destroyLoader(LOADER_ID_KEYBASE); + if (getLoaderManager().getLoader(LOADER_ID_CLOUD) != null) { + getLoaderManager().destroyLoader(LOADER_ID_CLOUD); } if (getView() != null) { setListShown(true); @@ -219,16 +205,11 @@ public class ImportKeysListFragment extends ListFragment implements setListShown(false); getLoaderManager().restartLoader(LOADER_ID_BYTES, null, this); - } else if (mLoaderState instanceof KeyserverLoaderState) { - // Start out with a progress indicator. - setListShown(false); - - getLoaderManager().restartLoader(LOADER_ID_SERVER_QUERY, null, this); - } else if (mLoaderState instanceof KeybaseLoaderState) { + } else if (mLoaderState instanceof CloudLoaderState) { // Start out with a progress indicator. setListShown(false); - getLoaderManager().restartLoader(LOADER_ID_KEYBASE, null, this); + getLoaderManager().restartLoader(LOADER_ID_CLOUD, null, this); } } @@ -241,13 +222,9 @@ public class ImportKeysListFragment extends ListFragment implements InputData inputData = getInputData(ls.keyBytes, ls.dataUri); return new ImportKeysListLoader(mActivity, inputData); } - case LOADER_ID_SERVER_QUERY: { - KeyserverLoaderState ls = (KeyserverLoaderState) mLoaderState; - return new ImportKeysListServerLoader(getActivity(), ls.serverQuery, ls.keyserver); - } - case LOADER_ID_KEYBASE: { - KeybaseLoaderState ls = (KeybaseLoaderState) mLoaderState; - return new ImportKeysListKeybaseLoader(getActivity(), ls.keybaseQuery); + case LOADER_ID_CLOUD: { + CloudLoaderState ls = (CloudLoaderState) mLoaderState; + return new ImportKeysListCloudLoader(getActivity(), ls.mServerQuery, ls.mCloudPrefs); } default: @@ -301,8 +278,7 @@ public class ImportKeysListFragment extends ListFragment implements } break; - case LOADER_ID_SERVER_QUERY: - case LOADER_ID_KEYBASE: + case LOADER_ID_CLOUD: if (error == null) { // No error @@ -333,11 +309,7 @@ public class ImportKeysListFragment extends ListFragment implements // Clear the data in the adapter. mAdapter.clear(); break; - case LOADER_ID_SERVER_QUERY: - // Clear the data in the adapter. - mAdapter.clear(); - break; - case LOADER_ID_KEYBASE: + case LOADER_ID_CLOUD: // Clear the data in the adapter. mAdapter.clear(); break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java deleted file mode 100644 index 88caebc32..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2013-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; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ContactHelper; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.List; - -public class ImportKeysServerFragment extends Fragment { - public static final String ARG_QUERY = "query"; - public static final String ARG_KEYSERVER = "keyserver"; - public static final String ARG_DISABLE_QUERY_EDIT = "disable_query_edit"; - - private ImportKeysActivity mImportActivity; - - private View mSearchButton; - private AutoCompleteTextView mQueryEditText; - private View mConfigButton; - private View mConfigLayout; - private Spinner mServerSpinner; - private ArrayAdapter mServerAdapter; - - /** - * Creates new instance of this fragment - */ - public static ImportKeysServerFragment newInstance(String query, String keyserver) { - ImportKeysServerFragment frag = new ImportKeysServerFragment(); - - Bundle args = new Bundle(); - args.putString(ARG_QUERY, query); - args.putString(ARG_KEYSERVER, keyserver); - - frag.setArguments(args); - - return frag; - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_server_fragment, container, false); - - mSearchButton = view.findViewById(R.id.import_server_search); - mQueryEditText = (AutoCompleteTextView) view.findViewById(R.id.import_server_query); - mConfigButton = view.findViewById(R.id.import_server_config_button); - mConfigLayout = view.findViewById(R.id.import_server_config); - mServerSpinner = (Spinner) view.findViewById(R.id.import_server_spinner); - - // add keyservers to spinner - mServerAdapter = new ArrayAdapter(getActivity(), - android.R.layout.simple_spinner_item, Preferences.getPreferences(getActivity()) - .getKeyServers() - ); - mServerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mServerSpinner.setAdapter(mServerAdapter); - if (mServerAdapter.getCount() > 0) { - mServerSpinner.setSelection(0); - } else { - mSearchButton.setEnabled(false); - } - - List namesAndEmails = ContactHelper.getContactNames(getActivity()); - namesAndEmails.addAll(ContactHelper.getContactMails(getActivity())); - mQueryEditText.setThreshold(3); - mQueryEditText.setAdapter( - new ArrayAdapter - (getActivity(), android.R.layout.simple_spinner_dropdown_item, - namesAndEmails - ) - ); - - mSearchButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - String query = mQueryEditText.getText().toString(); - String keyServer = (String) mServerSpinner.getSelectedItem(); - search(query, keyServer); - - // close keyboard after pressing search - InputMethodManager imm = - (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0); - } - }); - - mQueryEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_SEARCH) { - String query = mQueryEditText.getText().toString(); - String keyServer = (String) mServerSpinner.getSelectedItem(); - search(query, keyServer); - - // Don't return true to let the keyboard close itself after pressing search - return false; - } - return false; - } - }); - - mConfigButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mImportActivity.getViewPagerHeight() > ImportKeysActivity.VIEW_PAGER_HEIGHT) { - mImportActivity.resizeViewPager(ImportKeysActivity.VIEW_PAGER_HEIGHT); - } else { - mImportActivity.resizeViewPager(ImportKeysActivity.VIEW_PAGER_HEIGHT + 41); - } - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - // set displayed values - if (getArguments() != null) { - if (getArguments().containsKey(ARG_QUERY)) { - String query = getArguments().getString(ARG_QUERY); - mQueryEditText.setText(query, TextView.BufferType.EDITABLE); - - Log.d(Constants.TAG, "query: " + query); - } - - if (getArguments().containsKey(ARG_KEYSERVER)) { - String keyserver = getArguments().getString(ARG_KEYSERVER); - int keyserverPos = mServerAdapter.getPosition(keyserver); - mServerSpinner.setSelection(keyserverPos); - - Log.d(Constants.TAG, "keyserver: " + keyserver); - } - - if (getArguments().getBoolean(ARG_DISABLE_QUERY_EDIT, false)) { - mQueryEditText.setEnabled(false); - } - } - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - mImportActivity = (ImportKeysActivity) activity; - } - - private void search(String query, String keyserver) { - mImportActivity.loadCallback(new ImportKeysListFragment.KeyserverLoaderState(query, keyserver)); - } - - public void setQueryAndKeyserver(String query, String keyserver) { - mQueryEditText.setText(query, TextView.BufferType.EDITABLE); - int keyServerPos = mServerAdapter.getPosition(keyserver); - mServerSpinner.setSelection(keyServerPos); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java index 1221966e1..dd4fedf9d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.SuppressLint; +import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; @@ -40,7 +41,7 @@ import java.util.List; @SuppressLint("NewApi") public class PreferencesActivity extends PreferenceActivity { - public static final String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN"; + public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD"; public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; public static final int REQUEST_CODE_KEYSERVER_PREF = 0x00007005; @@ -55,16 +56,11 @@ public class PreferencesActivity extends PreferenceActivity { String action = getIntent().getAction(); - if (action != null && action.equals(ACTION_PREFS_GEN)) { - addPreferencesFromResource(R.xml.gen_preferences); - - initializePassPassphraceCacheTtl( - (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); + if (action != null && action.equals(ACTION_PREFS_CLOUD)) { + addPreferencesFromResource(R.xml.cloud_search_prefs); mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); - String servers[] = sPreferences.getKeyServers(); - mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_keyservers, - servers.length, servers.length)); + mKeyServerPreference.setSummary(keyserverSummary(this)); mKeyServerPreference .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { @@ -76,10 +72,19 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + initializeSearchKeyserver( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYSERVER) + ); + initializeSearchKeybase( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYBASE) + ); } else if (action != null && action.equals(ACTION_PREFS_ADV)) { addPreferencesFromResource(R.xml.adv_preferences); + initializePassPassphraceCacheTtl( + (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); + initializeEncryptionAlgorithm( (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); @@ -136,8 +141,7 @@ public class PreferencesActivity extends PreferenceActivity { String servers[] = data .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); sPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(getResources().getQuantityString( - R.plurals.n_keyservers, servers.length, servers.length)); + mKeyServerPreference.setSummary(keyserverSummary(this)); break; } @@ -156,9 +160,9 @@ public class PreferencesActivity extends PreferenceActivity { } /** - * This fragment shows the general preferences in android 3.0+ + * This fragment shows the Cloud Search preferences in android 3.0+ */ - public static class GeneralPrefsFragment extends PreferenceFragment { + public static class CloudSearchPrefsFragment extends PreferenceFragment { private PreferenceScreen mKeyServerPreference = null; @@ -167,15 +171,11 @@ public class PreferencesActivity extends PreferenceActivity { super.onCreate(savedInstanceState); // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.gen_preferences); - - initializePassPassphraceCacheTtl( - (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); + addPreferencesFromResource(R.xml.cloud_search_prefs); mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); - String servers[] = sPreferences.getKeyServers(); - mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_keyservers, - servers.length, servers.length)); + mKeyServerPreference.setSummary(keyserverSummary(getActivity())); + mKeyServerPreference .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { @@ -187,6 +187,12 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + initializeSearchKeyserver( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYSERVER) + ); + initializeSearchKeybase( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYBASE) + ); } @Override @@ -199,8 +205,7 @@ public class PreferencesActivity extends PreferenceActivity { String servers[] = data .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); sPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(getResources().getQuantityString( - R.plurals.n_keyservers, servers.length, servers.length)); + mKeyServerPreference.setSummary(keyserverSummary(getActivity())); break; } @@ -224,6 +229,9 @@ public class PreferencesActivity extends PreferenceActivity { // Load the preferences from an XML resource addPreferencesFromResource(R.xml.adv_preferences); + initializePassPassphraceCacheTtl( + (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); + initializeEncryptionAlgorithm( (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); @@ -271,7 +279,7 @@ public class PreferencesActivity extends PreferenceActivity { protected boolean isValidFragment(String fragmentName) { return AdvancedPrefsFragment.class.getName().equals(fragmentName) - || GeneralPrefsFragment.class.getName().equals(fragmentName) + || CloudSearchPrefsFragment.class.getName().equals(fragmentName) || super.isValidFragment(fragmentName); } @@ -398,6 +406,39 @@ public class PreferencesActivity extends PreferenceActivity { }); } + private static void initializeSearchKeyserver(final CheckBoxPreference mSearchKeyserver) { + Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs(); + mSearchKeyserver.setChecked(prefs.searchKeyserver); + mSearchKeyserver.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mSearchKeyserver.setChecked((Boolean) newValue); + sPreferences.setSearchKeyserver((Boolean) newValue); + return false; + } + }); + } + + private static void initializeSearchKeybase(final CheckBoxPreference mSearchKeybase) { + Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs(); + mSearchKeybase.setChecked(prefs.searchKeybase); + mSearchKeybase.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mSearchKeybase.setChecked((Boolean) newValue); + sPreferences.setSearchKeybase((Boolean) newValue); + return false; + } + }); + } + + public static String keyserverSummary(Context context) { + String[] servers = sPreferences.getKeyServers(); + String serverSummary = context.getResources().getQuantityString( + R.plurals.n_keyservers, servers.length, servers.length); + return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences.getPreferredKeyserver(); + } + private static void initializeUseDefaultYubikeyPin(final CheckBoxPreference mUseDefaultYubikeyPin) { mUseDefaultYubikeyPin.setChecked(sPreferences.useDefaultYubikeyPin()); mUseDefaultYubikeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @@ -408,4 +449,5 @@ public class PreferencesActivity extends PreferenceActivity { } }); } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java index 0de675bab..b5e0e2ab5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java @@ -43,6 +43,7 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O private LayoutInflater mInflater; private ViewGroup mEditors; private View mAdd; + private View mShuffle; private TextView mTitle; private TextView mSummary; @@ -73,6 +74,7 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O mTitle = (TextView) findViewById(R.id.title); mSummary = (TextView) findViewById(R.id.summary); + mSummary.setText(getText(R.string.label_first_keyserver_is_used)); mTitle.setText(R.string.label_keyservers); @@ -80,9 +82,29 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O mAdd = findViewById(R.id.add); mAdd.setOnClickListener(this); + mShuffle = findViewById(R.id.shuffle); + mShuffle.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + Vector servers = serverList(); + String first = servers.get(0); + if (first != null) { + servers.remove(0); + servers.add(first); + String[] dummy = {}; + makeServerList(servers.toArray(dummy)); + } + } + }); + Intent intent = getIntent(); String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS); + makeServerList(servers); + } + + private void makeServerList(String[] servers) { if (servers != null) { + mEditors.removeAllViews(); for (String serv : servers) { KeyServerEditor view = (KeyServerEditor) mInflater.inflate( R.layout.key_server_editor, mEditors, false); @@ -114,6 +136,18 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O finish(); } + private Vector serverList() { + Vector servers = new Vector(); + for (int i = 0; i < mEditors.getChildCount(); ++i) { + KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); + String tmp = editor.getValue(); + if (tmp.length() > 0) { + servers.add(tmp); + } + } + return servers; + } + private void okClicked() { Intent data = new Intent(); Vector servers = new Vector(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java new file mode 100644 index 000000000..d39feda76 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 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.adapter; + +import android.content.Context; +import android.support.v4.content.AsyncTaskLoader; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.keyimport.CloudSearch; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.ArrayList; + +public class ImportKeysListCloudLoader + extends AsyncTaskLoader>> { + Context mContext; + + + Preferences.CloudSearchPrefs mCloudPrefs; + String mServerQuery; + + private ArrayList mEntryList = new ArrayList(); + private AsyncTaskResultWrapper> mEntryListWrapper; + + public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs) { + super(context); + mContext = context; + mServerQuery = serverQuery; + mCloudPrefs = cloudPrefs; + } + + @Override + public AsyncTaskResultWrapper> loadInBackground() { + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); + + if (mServerQuery == null) { + Log.e(Constants.TAG, "mServerQuery is null!"); + return mEntryListWrapper; + } + + if (mServerQuery.startsWith("0x") && mServerQuery.length() == 42) { + Log.d(Constants.TAG, "This search is based on a unique fingerprint. Enforce a fingerprint check!"); + queryServer(true); + } else { + queryServer(false); + } + + return mEntryListWrapper; + } + + @Override + protected void onReset() { + super.onReset(); + + // Ensure the loader is stopped + onStopLoading(); + } + + @Override + protected void onStartLoading() { + forceLoad(); + } + + @Override + protected void onStopLoading() { + cancelLoad(); + } + + @Override + public void deliverResult(AsyncTaskResultWrapper> data) { + super.deliverResult(data); + } + + /** + * Query keyserver + */ + private void queryServer(boolean enforceFingerprint) { + try { + ArrayList searchResult = CloudSearch.search(mServerQuery, mCloudPrefs); + + mEntryList.clear(); + // add result to data + if (enforceFingerprint) { + String fingerprint = mServerQuery.substring(2); + Log.d(Constants.TAG, "fingerprint: " + fingerprint); + // query must return only one result! + if (searchResult.size() == 1) { + ImportKeysListEntry uniqueEntry = searchResult.get(0); + /* + * set fingerprint explicitly after query + * to enforce a check when the key is imported by KeychainIntentService + */ + uniqueEntry.setFingerprintHex(fingerprint); + uniqueEntry.setSelected(true); + mEntryList.add(uniqueEntry); + } + } else { + mEntryList.addAll(searchResult); + } + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); + } catch (Exception e) { + mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java deleted file mode 100644 index d2aefc220..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 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.adapter; - -import android.content.Context; -import android.support.v4.content.AsyncTaskLoader; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; -import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver; -import org.sufficientlysecure.keychain.keyimport.Keyserver; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; - -public class ImportKeysListKeybaseLoader - extends AsyncTaskLoader>> { - Context mContext; - - String mKeybaseQuery; - - private ArrayList mEntryList = new ArrayList(); - private AsyncTaskResultWrapper> mEntryListWrapper; - - public ImportKeysListKeybaseLoader(Context context, String keybaseQuery) { - super(context); - mContext = context; - mKeybaseQuery = keybaseQuery; - } - - @Override - public AsyncTaskResultWrapper> loadInBackground() { - - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); - - if (mKeybaseQuery == null) { - Log.e(Constants.TAG, "mKeybaseQery is null!"); - return mEntryListWrapper; - } - - queryServer(mKeybaseQuery); - - return mEntryListWrapper; - } - - @Override - protected void onReset() { - super.onReset(); - - // Ensure the loader is stopped - onStopLoading(); - } - - @Override - protected void onStartLoading() { - forceLoad(); - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - public void deliverResult(AsyncTaskResultWrapper> data) { - super.deliverResult(data); - } - - /** - * Query keybase - */ - private void queryServer(String query) { - - KeybaseKeyserver server = new KeybaseKeyserver(); - try { - ArrayList searchResult = server.search(query); - - mEntryList.clear(); - - mEntryList.addAll(searchResult); - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); - } catch (Keyserver.QueryFailedException e) { - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); - } catch (Keyserver.QueryNeedsRepairException e) { - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java deleted file mode 100644 index d62c2db43..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 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.adapter; - -import android.content.Context; -import android.support.v4.content.AsyncTaskLoader; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; -import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; -import org.sufficientlysecure.keychain.keyimport.Keyserver; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; - -public class ImportKeysListServerLoader - extends AsyncTaskLoader>> { - Context mContext; - - String mServerQuery; - String mKeyServer; - - private ArrayList mEntryList = new ArrayList(); - private AsyncTaskResultWrapper> mEntryListWrapper; - - public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) { - super(context); - mContext = context; - mServerQuery = serverQuery; - mKeyServer = keyServer; - } - - @Override - public AsyncTaskResultWrapper> loadInBackground() { - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); - - if (mServerQuery == null) { - Log.e(Constants.TAG, "mServerQuery is null!"); - return mEntryListWrapper; - } - - if (mServerQuery.startsWith("0x") && mServerQuery.length() == 42) { - Log.d(Constants.TAG, "This search is based on a unique fingerprint. Enforce a fingerprint check!"); - queryServer(mServerQuery, mKeyServer, true); - } else { - queryServer(mServerQuery, mKeyServer, false); - } - - return mEntryListWrapper; - } - - @Override - protected void onReset() { - super.onReset(); - - // Ensure the loader is stopped - onStopLoading(); - } - - @Override - protected void onStartLoading() { - forceLoad(); - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - public void deliverResult(AsyncTaskResultWrapper> data) { - super.deliverResult(data); - } - - /** - * Query keyserver - */ - private void queryServer(String query, String keyServer, boolean enforceFingerprint) { - HkpKeyserver server = new HkpKeyserver(keyServer); - try { - ArrayList searchResult = server.search(query); - - mEntryList.clear(); - // add result to data - if (enforceFingerprint) { - String fingerprint = query.substring(2); - Log.d(Constants.TAG, "fingerprint: " + fingerprint); - // query must return only one result! - if (searchResult.size() == 1) { - ImportKeysListEntry uniqueEntry = searchResult.get(0); - /* - * set fingerprint explicitly after query - * to enforce a check when the key is imported by KeychainIntentService - */ - uniqueEntry.setFingerprintHex(fingerprint); - uniqueEntry.setSelected(true); - mEntryList.add(uniqueEntry); - } - } else { - mEntryList.addAll(searchResult); - } - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); - } catch (Keyserver.QueryFailedException e) { - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); - } catch (Keyserver.QueryNeedsRepairException e) { - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); - } - } - -} diff --git a/OpenKeychain/src/main/res/drawable/button_rounded_blue.xml b/OpenKeychain/src/main/res/drawable/button_rounded_blue.xml new file mode 100644 index 000000000..7e36b0ef8 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable/button_rounded_blue.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/import_keys_cloud_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_cloud_fragment.xml new file mode 100644 index 000000000..46ec736ca --- /dev/null +++ b/OpenKeychain/src/main/res/layout/import_keys_cloud_fragment.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml deleted file mode 100644 index c70236e07..000000000 --- a/OpenKeychain/src/main/res/layout/import_keys_keybase_fragment.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/import_keys_list_entry.xml b/OpenKeychain/src/main/res/layout/import_keys_list_entry.xml index 773250dc6..74de77172 100644 --- a/OpenKeychain/src/main/res/layout/import_keys_list_entry.xml +++ b/OpenKeychain/src/main/res/layout/import_keys_list_entry.xml @@ -30,6 +30,8 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingRight="8dp" + android:paddingTop="2dp" + android:gravity="top|center" android:clickable="false" android:focusable="false" android:focusableInTouchMode="false" /> diff --git a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml deleted file mode 100644 index 62e7d740c..000000000 --- a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/key_server_preference.xml b/OpenKeychain/src/main/res/layout/key_server_preference.xml index baf7111af..140b5e3d7 100644 --- a/OpenKeychain/src/main/res/layout/key_server_preference.xml +++ b/OpenKeychain/src/main/res/layout/key_server_preference.xml @@ -12,7 +12,7 @@ android:minHeight="?android:attr/listPreferredItemHeight" android:orientation="horizontal" > - - - + +