diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index a83992d09..fcdbe6bce 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -58,7 +58,6 @@ - @@ -138,11 +137,6 @@ android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:label="@string/title_select_recipients" android:launchMode="singleTop" /> - + + + + + + + + + + + + + + + + + + + + @@ -214,12 +236,6 @@ - - - - - - @@ -235,7 +251,12 @@ - + + + + + + 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/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index b745aec38..612077e34 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.service.results.OperationResult.LogType; import org.sufficientlysecure.keychain.service.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Utf8Util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -363,7 +364,7 @@ public class UncachedKeyRing { ArrayList processedUserIds = new ArrayList(); for (byte[] rawUserId : new IterableIterator(masterKey.getRawUserIDs())) { - String userId = Strings.fromUTF8ByteArray(rawUserId); + String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); // check for duplicate user ids if (processedUserIds.contains(rawUserId)) { @@ -437,7 +438,7 @@ public class UncachedKeyRing { continue; } // warn user if the signature was made with bad encoding - if (!cert.verifySignature(masterKey, userId)) { + if (!Utf8Util.isValidUTF8(rawUserId)) { log.add(LogType.MSG_KC_UID_WARN_ENCODING, indent); } } catch (PgpGeneralException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index e27190bc7..7f08d121e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -32,6 +32,7 @@ import org.spongycastle.util.Strings; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Utf8Util; import java.util.ArrayList; import java.util.Arrays; @@ -185,7 +186,7 @@ public class UncachedPublicKey { } } if (found != null) { - return Strings.fromUTF8ByteArray(found); + return Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(found); } else { return null; } @@ -204,8 +205,9 @@ public class UncachedPublicKey { public ArrayList getUnorderedUserIds() { ArrayList userIds = new ArrayList(); - for (String userId : new IterableIterator(mPublicKey.getUserIDs())) { - userIds.add(userId); + for (byte[] rawUserId : new IterableIterator(mPublicKey.getRawUserIDs())) { + // use our decoding method + userIds.add(Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId)); } return userIds; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 0706edb2b..702da275a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -65,6 +65,7 @@ import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressFixedScaler; import org.sufficientlysecure.keychain.util.ProgressScaler; +import org.sufficientlysecure.keychain.util.Utf8Util; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -437,8 +438,7 @@ public class ProviderHelper { List uids = new ArrayList(); for (byte[] rawUserId : new IterableIterator( masterKey.getUnorderedRawUserIds().iterator())) { - String userId = Strings.fromUTF8ByteArray(rawUserId); - Log.d(Constants.TAG, "userId: "+userId); + String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); UserIdItem item = new UserIdItem(); uids.add(item); 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 2c2c9f488..19248dfa3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -651,27 +651,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/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 998ed34cd..37382051b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -1,6 +1,5 @@ /* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2010-2014 Thialfihar + * 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 @@ -19,148 +18,40 @@ 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 android.view.View; -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()); + View actionFile = findViewById(R.id.decrypt_files); + View actionFromClipboard = findViewById(R.id.decrypt_from_clipboard); - 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; + actionFile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent filesDecrypt = new Intent(DecryptActivity.this, DecryptFilesActivity.class); + filesDecrypt.setAction(DecryptFilesActivity.ACTION_DECRYPT_DATA_OPEN); + startActivity(filesDecrypt); } - } 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!"); - } + actionFromClipboard.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent clipboardDecrypt = new Intent(DecryptActivity.this, DecryptTextActivity.class); + clipboardDecrypt.setAction(DecryptTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD); + startActivity(clipboardDecrypt); } - } 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/DecryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java new file mode 100644 index 000000000..9d972d8c0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java @@ -0,0 +1,113 @@ +/* + * 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.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.api.OpenKeychainIntents; +import org.sufficientlysecure.keychain.util.Log; + +public class DecryptFilesActivity extends ActionBarActivity { + + /* Intents */ + public static final String ACTION_DECRYPT_DATA = OpenKeychainIntents.DECRYPT_DATA; + + // intern + public static final String ACTION_DECRYPT_DATA_OPEN = Constants.INTENT_PREFIX + "DECRYPT_DATA_OPEN"; + + DecryptFilesFragment mFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.decrypt_files_activity); + + // Handle intent actions + handleActions(savedInstanceState, getIntent()); + } + + /** + * Handles all actions with this intent + * + * @param intent + */ + private void handleActions(Bundle savedInstanceState, Intent intent) { + String action = intent.getAction(); + String type = intent.getType(); + Uri uri = intent.getData(); + + Bundle mFileFragmentBundle = new Bundle(); + + /* + * Android's Action + */ + if (Intent.ACTION_SEND.equals(action) && type != null) { + // When sending to Keychain Decrypt via share menu + // Binary via content provider (could also be files) + // override uri to get stream from send + uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); + action = ACTION_DECRYPT_DATA; + } else if (Intent.ACTION_VIEW.equals(action)) { + // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) + + // override action + action = ACTION_DECRYPT_DATA; + } + + /** + * Main Actions + */ + if (ACTION_DECRYPT_DATA.equals(action) && uri != null) { + mFileFragmentBundle.putParcelable(DecryptFilesFragment.ARG_URI, uri); + + loadFragment(savedInstanceState, uri, false); + } else if (ACTION_DECRYPT_DATA_OPEN.equals(action)) { + loadFragment(savedInstanceState, null, true); + } else if (ACTION_DECRYPT_DATA.equals(action)) { + Log.e(Constants.TAG, + "Include an Uri with setData() in your Intent!"); + } + } + + private void loadFragment(Bundle savedInstanceState, Uri uri, boolean openDialog) { + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } + + // Create an instance of the fragment + mFragment = DecryptFilesFragment.newInstance(uri, openDialog); + + // Add the fragment to the 'fragment_container' FrameLayout + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! + getSupportFragmentManager().beginTransaction() + .replace(R.id.decrypt_files_fragment_container, mFragment) + .commitAllowingStateLoss(); + // do it immediately! + getSupportFragmentManager().executePendingTransactions(); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java similarity index 91% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index 924c5bec2..f5d6eba1b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -46,9 +46,10 @@ import org.sufficientlysecure.keychain.util.Notify; import java.io.File; -public class DecryptFileFragment extends DecryptFragment { +public class DecryptFilesFragment extends DecryptFragment { public static final String ARG_URI = "uri"; - public static final String ARG_FROM_VIEW_INTENT = "view_intent"; +// public static final String ARG_FROM_VIEW_INTENT = "view_intent"; + public static final String ARG_OPEN_DIRECTLY = "open_directly"; private static final int REQUEST_CODE_INPUT = 0x00007003; private static final int REQUEST_CODE_OUTPUT = 0x00007007; @@ -62,6 +63,22 @@ public class DecryptFileFragment extends DecryptFragment { private Uri mInputUri = null; private Uri mOutputUri = null; + /** + * Creates new instance of this fragment + */ + public static DecryptFilesFragment newInstance(Uri uri, boolean openDirectly) { + DecryptFilesFragment frag = new DecryptFilesFragment(); + + Bundle args = new Bundle(); + args.putParcelable(ARG_URI, uri); +// args.putBoolean(ARG_FROM_VIEW_INTENT, fromViewIntent); + args.putBoolean(ARG_OPEN_DIRECTLY, openDirectly); + + frag.setArguments(args); + + return frag; + } + /** * Inflate the layout for this fragment */ @@ -75,9 +92,9 @@ public class DecryptFileFragment extends DecryptFragment { view.findViewById(R.id.decrypt_file_browse).setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - FileHelper.openDocument(DecryptFileFragment.this, "*/*", REQUEST_CODE_INPUT); + FileHelper.openDocument(DecryptFilesFragment.this, "*/*", REQUEST_CODE_INPUT); } else { - FileHelper.openFile(DecryptFileFragment.this, mInputUri, "*/*", + FileHelper.openFile(DecryptFilesFragment.this, mInputUri, "*/*", REQUEST_CODE_INPUT); } } @@ -97,6 +114,15 @@ public class DecryptFileFragment extends DecryptFragment { super.onActivityCreated(savedInstanceState); setInputUri(getArguments().getParcelable(ARG_URI)); + + if (getArguments().getBoolean(ARG_OPEN_DIRECTLY, false)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + FileHelper.openDocument(DecryptFilesFragment.this, "*/*", REQUEST_CODE_INPUT); + } else { + FileHelper.openFile(DecryptFilesFragment.this, mInputUri, "*/*", + REQUEST_CODE_INPUT); + } + } } private void setInputUri(Uri inputUri) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java new file mode 100644 index 000000000..5d46b351b --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -0,0 +1,158 @@ +/* + * 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.os.Bundle; +import android.support.v7.app.ActionBarActivity; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.api.OpenKeychainIntents; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Notify; + +import java.util.regex.Matcher; + +public class DecryptTextActivity extends ActionBarActivity { + + /* Intents */ + public static final String ACTION_DECRYPT_TEXT = OpenKeychainIntents.DECRYPT_TEXT; + public static final String EXTRA_TEXT = OpenKeychainIntents.DECRYPT_EXTRA_TEXT; + + // intern + public static final String ACTION_DECRYPT_FROM_CLIPBOARD = Constants.INTENT_PREFIX + "DECRYPT_TEXT_FROM_CLIPBOARD"; + + DecryptTextFragment mFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.decrypt_text_activity); + + // Handle intent actions + handleActions(savedInstanceState, getIntent()); + } + + /** + * Handles all actions with this intent + * + * @param intent + */ + private void handleActions(Bundle savedInstanceState, Intent intent) { + String action = intent.getAction(); + Bundle extras = intent.getExtras(); + String type = intent.getType(); + + if (extras == null) { + extras = new Bundle(); + } + + String textData = null; + + /* + * 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_TEXT in main actions + textData = sharedText; + } + } + } + + /** + * Main Actions + */ + textData = extras.getString(EXTRA_TEXT); + if (ACTION_DECRYPT_TEXT.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", " "); + } 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", " "); + } else { + Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR); + Log.d(Constants.TAG, "Nothing matched!"); + } + } + } else if (ACTION_DECRYPT_FROM_CLIPBOARD.equals(action)) { + CharSequence clipboardText = ClipboardReflection.getClipboardText(this); + + // only decrypt if clipboard content is available and a pgp message or cleartext signature + if (clipboardText != null) { + Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText); + if (!matcher.matches()) { + matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText); + } + if (matcher.matches()) { + textData = matcher.group(1); + } else { + Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR); + } + } else { + Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR); + } + } else if (ACTION_DECRYPT_TEXT.equals(action)) { + Log.e(Constants.TAG, + "Include the extra 'text' in your Intent!"); + } + + loadFragment(savedInstanceState, textData); + } + + + private void loadFragment(Bundle savedInstanceState, String ciphertext) { + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } + + // Create an instance of the fragment + mFragment = DecryptTextFragment.newInstance(ciphertext); + + // Add the fragment to the 'fragment_container' FrameLayout + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! + getSupportFragmentManager().beginTransaction() + .replace(R.id.decrypt_text_fragment_container, mFragment) + .commitAllowingStateLoss(); + // do it immediately! + getSupportFragmentManager().executePendingTransactions(); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java similarity index 68% rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 66ed563d9..c1bc563f8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -24,62 +24,70 @@ import android.os.Message; import android.os.Messenger; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.EditText; +import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Notify; -import java.util.regex.Matcher; - -public class DecryptMessageFragment extends DecryptFragment { +public class DecryptTextFragment extends DecryptFragment { public static final String ARG_CIPHERTEXT = "ciphertext"; - // view - private EditText mMessage; - private View mDecryptButton; - private View mDecryptFromCLipboardButton; - - // model +// // view + private TextView mMessage; +// private View mDecryptButton; +// private View mDecryptFromCLipboardButton; +// +// // model private String mCiphertext; + /** + * Creates new instance of this fragment + */ + public static DecryptTextFragment newInstance(String ciphertext) { + DecryptTextFragment frag = new DecryptTextFragment(); + + Bundle args = new Bundle(); + args.putString(ARG_CIPHERTEXT, ciphertext); + + 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.decrypt_message_fragment, container, false); + View view = inflater.inflate(R.layout.decrypt_text_fragment, container, false); - mMessage = (EditText) view.findViewById(R.id.message); - mDecryptButton = view.findViewById(R.id.action_decrypt); - mDecryptFromCLipboardButton = view.findViewById(R.id.action_decrypt_from_clipboard); - mDecryptButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - decryptClicked(); - } - }); - mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - decryptFromClipboardClicked(); - } - }); + mMessage = (TextView) view.findViewById(R.id.decrypt_text_plaintext); +// mDecryptButton = view.findViewById(R.id.action_decrypt); +// mDecryptFromCLipboardButton = view.findViewById(R.id.action_decrypt_from_clipboard); +// mDecryptButton.setOnClickListener(new OnClickListener() { +// @Override +// public void onClick(View v) { +// decryptClicked(); +// } +// }); +// mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() { +// @Override +// public void onClick(View v) { +// decryptFromClipboardClicked(); +// } +// }); return view; } @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); String ciphertext = getArguments().getString(ARG_CIPHERTEXT); if (ciphertext != null) { @@ -88,31 +96,6 @@ public class DecryptMessageFragment extends DecryptFragment { } } - private void decryptClicked() { - mCiphertext = mMessage.getText().toString(); - decryptStart(null); - } - - private void decryptFromClipboardClicked() { - CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); - - // only decrypt if clipboard content is available and a pgp message or cleartext signature - if (clipboardText != null) { - Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText); - if (!matcher.matches()) { - matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText); - } - if (matcher.matches()) { - mCiphertext = matcher.group(1); - decryptStart(null); - } else { - Notify.showNotify(getActivity(), R.string.error_invalid_data, Notify.Style.ERROR); - } - } else { - Notify.showNotify(getActivity(), R.string.error_invalid_data, Notify.Style.ERROR); - } - } - @Override protected void decryptStart(String passphrase) { Log.d(Constants.TAG, "decryptStart"); 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/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 57bfc7bd5..9d448c1e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -113,7 +113,7 @@ public class UploadKeyActivity extends ActionBarActivity { if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - Toast.makeText(UploadKeyActivity.this, R.string.key_send_success, + Toast.makeText(UploadKeyActivity.this, R.string.msg_crt_upload_success, Toast.LENGTH_SHORT).show(); finish(); } 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/java/org/sufficientlysecure/keychain/util/Utf8Util.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Utf8Util.java new file mode 100644 index 000000000..bed3e28ed --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Utf8Util.java @@ -0,0 +1,53 @@ +/* + * 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.util; + +import org.sufficientlysecure.keychain.Constants; + +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; + +public class Utf8Util { + + public static boolean isValidUTF8(byte[] input) { + CharsetDecoder cs = Charset.forName("UTF-8").newDecoder(); + + try { + cs.decode(ByteBuffer.wrap(input)); + return true; + } catch (CharacterCodingException e) { + return false; + } + } + + public static String fromUTF8ByteArrayReplaceBadEncoding(byte[] input) { + final CharsetDecoder charsetDecoder = Charset.forName("UTF-8").newDecoder(); + charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE); + charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + + try { + return charsetDecoder.decode(ByteBuffer.wrap(input)).toString(); + } catch (CharacterCodingException e) { + Log.e(Constants.TAG, "Decoding failed!", e); + return charsetDecoder.replacement(); + } + } +} 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-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_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 index f62cf615c..1fa6ea848 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_content.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_content.xml @@ -8,17 +8,71 @@ - + android:layout_height="match_parent" + android:paddingTop="4dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:orientation="vertical"> - - + android:layout_marginTop="16dp" + android:text="Files" /> + + + + + + + + + + + + + \ 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 diff --git a/OpenKeychain/src/main/res/layout/decrypt_files_activity.xml b/OpenKeychain/src/main/res/layout/decrypt_files_activity.xml new file mode 100644 index 000000000..0380787db --- /dev/null +++ b/OpenKeychain/src/main/res/layout/decrypt_files_activity.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml b/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml new file mode 100644 index 000000000..e08ecb39e --- /dev/null +++ b/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/decrypt_message_fragment.xml b/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml similarity index 81% rename from OpenKeychain/src/main/res/layout/decrypt_message_fragment.xml rename to OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml index 3b4eba3ef..5e9189fd3 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_message_fragment.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml @@ -25,24 +25,25 @@ android:paddingRight="16dp" android:orientation="vertical"> - - + android:layout_weight="1" + android:textIsSelectable="true" /> + @@ -70,11 +73,11 @@ android:background="?android:attr/listDivider" /> diff --git a/OpenKeychain/src/main/res/layout/encrypt_file_content.xml b/OpenKeychain/src/main/res/layout/encrypt_file_content.xml index 34f6eadda..5bf652780 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_file_content.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_file_content.xml @@ -16,7 +16,7 @@ android:orientation="vertical" /> diff --git a/OpenKeychain/src/main/res/layout/encrypt_text_content.xml b/OpenKeychain/src/main/res/layout/encrypt_text_content.xml index ee87b8a7e..809f00204 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_text_content.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_text_content.xml @@ -16,7 +16,7 @@ android:orientation="vertical" /> 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" > - - - + +