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/KeyUpdateHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/KeyUpdateHelper.java index 9ca6d5c5b..0a804fa64 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/KeyUpdateHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/KeyUpdateHelper.java @@ -63,7 +63,7 @@ public class KeyUpdateHelper { ImportKeysListEntry key = new ImportKeysListEntry(); key.setFingerprintHex(fprint); key.setBitStrength(1337); - key.setOrigin(servers[0]); + key.addOrigin(servers[0]); keys.add(key); } 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/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index c4c12cd3a..a6f1334ea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -278,7 +278,7 @@ public class HkpKeyserver extends Keyserver { while (matcher.find()) { final ImportKeysListEntry entry = new ImportKeysListEntry(); entry.setQuery(query); - entry.setOrigin(getUrlPrefix() + mHost + ":" + mPort); + entry.addOrigin(getUrlPrefix() + mHost + ":" + mPort); int bitSize = Integer.parseInt(matcher.group(3)); entry.setBitStrength(bitSize); 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..15bcd8576 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java @@ -0,0 +1,95 @@ +/* + * 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 mergeDupes(toAdd, existing); + } + } + return super.add(toAdd); + } + + // being a little anal about the ArrayList#addAll contract here + private boolean mergeDupes(ImportKeysListEntry incoming, ImportKeysListEntry existing) { + boolean modified = false; + if (incoming.isRevoked()) { + existing.setRevoked(true); + modified = true; + } + if (incoming.isExpired()) { + existing.setExpired(true); + modified = true; + } + for (String origin : incoming.getOrigins()) { + existing.addOrigin(origin); + } + 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..b3df67c0c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -46,7 +46,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { private String mPrimaryUserId; private String mExtraData; private String mQuery; - private String mOrigin; + private ArrayList mOrigins; private Integer mHashCode = null; private boolean mSelected; @@ -70,7 +70,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { dest.writeByte((byte) (mSecretKey ? 1 : 0)); dest.writeByte((byte) (mSelected ? 1 : 0)); dest.writeString(mExtraData); - dest.writeString(mOrigin); + dest.writeStringList(mOrigins); } public static final Creator CREATOR = new Creator() { @@ -90,7 +90,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.mSecretKey = source.readByte() == 1; vr.mSelected = source.readByte() == 1; vr.mExtraData = source.readString(); - vr.mOrigin = source.readString(); + vr.mOrigins = new ArrayList(); + source.readStringList(vr.mOrigins); return vr; } @@ -107,6 +108,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; } @@ -223,12 +231,12 @@ public class ImportKeysListEntry implements Serializable, Parcelable { mQuery = query; } - public String getOrigin() { - return mOrigin; + public ArrayList getOrigins() { + return mOrigins; } - public void setOrigin(String origin) { - mOrigin = origin; + public void addOrigin(String origin) { + mOrigins.add(origin); } /** @@ -240,6 +248,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { // do not select by default mSelected = false; mUserIds = new ArrayList(); + mOrigins = new ArrayList(); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java index cbd06da90..0a55fccc8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java @@ -63,7 +63,9 @@ public class KeybaseKeyserver extends Keyserver { private ImportKeysListEntry makeEntry(Match match) throws KeybaseException { final ImportKeysListEntry entry = new ImportKeysListEntry(); entry.setQuery(mQuery); - entry.setOrigin(ORIGIN); + entry.addOrigin(ORIGIN); + + entry.setRevoked(false); // keybase doesn’t say anything about revoked keys String username = match.getUsername(); String fullName = match.getFullName(); 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/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 52638f592..9b7dcaf6a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -652,27 +652,35 @@ public class KeychainIntentService extends IntentService implements Progressable for (ImportKeysListEntry entry : entries) { try { Keyserver server; - if (entry.getOrigin() == null) { - server = new HkpKeyserver(keyServer); - } else if (KeybaseKeyserver.ORIGIN.equals(entry.getOrigin())) { - server = new KeybaseKeyserver(); - } else { - server = new HkpKeyserver(entry.getOrigin()); + ArrayList origins = entry.getOrigins(); + if (origins == null) { + origins = new ArrayList(); } - - // if available use complete fingerprint for get request - byte[] downloadedKeyBytes; - if (KeybaseKeyserver.ORIGIN.equals(entry.getOrigin())) { - downloadedKeyBytes = server.get(entry.getExtraData()).getBytes(); - } else if (entry.getFingerprintHex() != null) { - downloadedKeyBytes = server.get("0x" + entry.getFingerprintHex()).getBytes(); - } else { - downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); + if (origins.isEmpty()) { + origins.add(keyServer); } + for (String origin : origins) { + if (KeybaseKeyserver.ORIGIN.equals(origin)) { + server = new KeybaseKeyserver(); + } else { + server = new HkpKeyserver(origin); + } + Log.d(Constants.TAG, "IMPORTING " + entry.getKeyIdHex() + " FROM: " + server); - // save key bytes in entry object for doing the - // actual import afterwards - keyRings.add(new ParcelableKeyRing(downloadedKeyBytes, entry.getFingerprintHex())); + // if available use complete fingerprint for get request + byte[] downloadedKeyBytes; + if (KeybaseKeyserver.ORIGIN.equals(origin)) { + downloadedKeyBytes = server.get(entry.getExtraData()).getBytes(); + } else if (entry.getFingerprintHex() != null) { + downloadedKeyBytes = server.get("0x" + entry.getFingerprintHex()).getBytes(); + } else { + downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); + } + + // save key bytes in entry object for doing the + // actual import afterwards + keyRings.add(new ParcelableKeyRing(downloadedKeyBytes, entry.getFingerprintHex())); + } } catch (Exception e) { sendErrorToHandler(e); } 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,7 +517,7 @@ public class ImportKeysActivity extends ActionBarActivity { // fill values for this action Bundle data = new Bundle(); - data.putString(KeychainIntentService.DOWNLOAD_KEY_SERVER, sls.keyserver); + data.putString(KeychainIntentService.DOWNLOAD_KEY_SERVER, sls.mCloudPrefs.keyserver); // get selected key entries ArrayList selectedEntries = mListFragment.getSelectedEntries(); @@ -550,31 +534,6 @@ public class ImportKeysActivity extends ActionBarActivity { // 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(); - - // 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 { Notify.showNotify(this, R.string.error_nothing_import, Notify.Style.ERROR); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java similarity index 62% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java index 88caebc32..6b4b833c6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -19,6 +19,7 @@ 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; @@ -30,8 +31,6 @@ 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; @@ -42,9 +41,8 @@ import org.sufficientlysecure.keychain.util.Log; import java.util.List; -public class ImportKeysServerFragment extends Fragment { +public class ImportKeysCloudFragment 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; @@ -52,19 +50,16 @@ public class ImportKeysServerFragment extends Fragment { 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(); + 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); - args.putString(ARG_KEYSERVER, keyserver); frag.setArguments(args); @@ -76,26 +71,11 @@ public class ImportKeysServerFragment extends Fragment { */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_server_fragment, container, false); + View view = inflater.inflate(R.layout.import_keys_cloud_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); - } + 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())); @@ -110,9 +90,7 @@ public class ImportKeysServerFragment extends Fragment { mSearchButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - String query = mQueryEditText.getText().toString(); - String keyServer = (String) mServerSpinner.getSelectedItem(); - search(query, keyServer); + search(mQueryEditText.getText().toString()); // close keyboard after pressing search InputMethodManager imm = @@ -125,9 +103,7 @@ public class ImportKeysServerFragment extends Fragment { @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); + search(mQueryEditText.getText().toString()); // Don't return true to let the keyboard close itself after pressing search return false; @@ -139,11 +115,11 @@ public class ImportKeysServerFragment extends Fragment { 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); - } + 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); } }); @@ -163,14 +139,6 @@ public class ImportKeysServerFragment extends Fragment { 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); } @@ -184,14 +152,9 @@ public class ImportKeysServerFragment extends Fragment { 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); + 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) { + } else if (mLoaderState instanceof CloudLoaderState) { // Start out with a progress indicator. setListShown(false); - getLoaderManager().restartLoader(LOADER_ID_SERVER_QUERY, null, this); - } else if (mLoaderState instanceof KeybaseLoaderState) { - // 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/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..520f0b6a5 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 mRotate; 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); + mRotate = findViewById(R.id.rotate); + mRotate.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/ImportKeysListServerLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java similarity index 79% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java index d62c2db43..d39feda76 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -21,28 +21,29 @@ 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.helper.Preferences; +import org.sufficientlysecure.keychain.keyimport.CloudSearch; 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 +public class ImportKeysListCloudLoader extends AsyncTaskLoader>> { Context mContext; + + Preferences.CloudSearchPrefs mCloudPrefs; String mServerQuery; - String mKeyServer; private ArrayList mEntryList = new ArrayList(); private AsyncTaskResultWrapper> mEntryListWrapper; - public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) { + public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs) { super(context); mContext = context; mServerQuery = serverQuery; - mKeyServer = keyServer; + mCloudPrefs = cloudPrefs; } @Override @@ -56,9 +57,9 @@ public class ImportKeysListServerLoader 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); + queryServer(true); } else { - queryServer(mServerQuery, mKeyServer, false); + queryServer(false); } return mEntryListWrapper; @@ -90,15 +91,14 @@ public class ImportKeysListServerLoader /** * Query keyserver */ - private void queryServer(String query, String keyServer, boolean enforceFingerprint) { - HkpKeyserver server = new HkpKeyserver(keyServer); + private void queryServer(boolean enforceFingerprint) { try { - ArrayList searchResult = server.search(query); + ArrayList searchResult = CloudSearch.search(mServerQuery, mCloudPrefs); mEntryList.clear(); // add result to data if (enforceFingerprint) { - String fingerprint = query.substring(2); + String fingerprint = mServerQuery.substring(2); Log.d(Constants.TAG, "fingerprint: " + fingerprint); // query must return only one result! if (searchResult.size() == 1) { @@ -115,11 +115,8 @@ public class ImportKeysListServerLoader mEntryList.addAll(searchResult); } mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); - } catch (Keyserver.QueryFailedException e) { - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, e); - } catch (Keyserver.QueryNeedsRepairException e) { + } 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/res/drawable/button_rounded_blue.xml b/OpenKeychain/src/main/res/drawable/button_rounded_blue.xml new file mode 100644 index 000000000..2f5009478 --- /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_server_fragment.xml b/OpenKeychain/src/main/res/layout/import_keys_cloud_fragment.xml similarity index 68% rename from OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml rename to OpenKeychain/src/main/res/layout/import_keys_cloud_fragment.xml index 62e7d740c..46ec736ca 100644 --- a/OpenKeychain/src/main/res/layout/import_keys_server_fragment.xml +++ b/OpenKeychain/src/main/res/layout/import_keys_cloud_fragment.xml @@ -11,12 +11,12 @@ android:orientation="horizontal"> - - - - - - - \ 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/key_server_preference.xml b/OpenKeychain/src/main/res/layout/key_server_preference.xml index baf7111af..33866f746 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" > - - - + +