aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-04-26 01:02:22 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2015-04-26 01:02:22 +0200
commit1865852cccccf0b78ffe8bcdc0cfbca66ddebfdc (patch)
treeadd2f0d85813f9ece1be3c926b4ae8f221d7cf47
parentd6d678dae3ed5d794a9aa5e289197d264f6a7ff9 (diff)
parentc442d3bd0d3bac96614d3d5c0e833a42cab4706e (diff)
downloadopen-keychain-1865852cccccf0b78ffe8bcdc0cfbca66ddebfdc.tar.gz
open-keychain-1865852cccccf0b78ffe8bcdc0cfbca66ddebfdc.tar.bz2
open-keychain-1865852cccccf0b78ffe8bcdc0cfbca66ddebfdc.zip
Merge remote-tracking branch 'origin/development' into linked-identities
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java OpenKeychain/src/main/res/menu/decrypt_menu.xml
-rwxr-xr-xGraphics/get-material-icons.sh2
-rw-r--r--OpenKeychain/build.gradle31
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java19
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java93
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java56
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java60
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java19
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java178
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java60
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java43
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java320
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthBarView.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java)5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java)3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java5
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.pngbin0 -> 284 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.pngbin0 -> 499 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.pngbin0 -> 214 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.pngbin0 -> 355 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.pngbin0 -> 304 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.pngbin0 -> 614 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.pngbin0 -> 397 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.pngbin0 -> 804 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.pngbin0 -> 480 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.pngbin0 -> 1052 bytes
-rw-r--r--OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml29
-rw-r--r--OpenKeychain/src/main/res/layout/decrypt_text_activity.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml27
-rw-r--r--OpenKeychain/src/main/res/layout/main_activity.xml19
-rw-r--r--OpenKeychain/src/main/res/layout/main_drawer_header.xml9
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml145
-rw-r--r--OpenKeychain/src/main/res/menu/decrypt_menu.xml6
-rw-r--r--OpenKeychain/src/main/res/raw/help_about.md29
-rw-r--r--OpenKeychain/src/main/res/raw/help_changelog.md14
-rw-r--r--OpenKeychain/src/main/res/values/colors.xml1
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml16
-rw-r--r--OpenKeychain/src/main/res/values/themes.xml11
55 files changed, 1113 insertions, 238 deletions
diff --git a/Graphics/get-material-icons.sh b/Graphics/get-material-icons.sh
index 299ae9713..11e0cda18 100755
--- a/Graphics/get-material-icons.sh
+++ b/Graphics/get-material-icons.sh
@@ -41,6 +41,8 @@ python copy OpenKeychain navigation grey chevron_left 24
python copy OpenKeychain navigation grey chevron_right 24
python copy OpenKeychain social grey person 48
python copy OpenKeychain communication grey email 24
+python copy OpenKeychain social black share 24
+python copy OpenKeychain content black content_copy 24
# navigation drawer sections
python copy OpenKeychain communication black vpn_key 24
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle
index 27be5634c..7d6cf17b9 100644
--- a/OpenKeychain/build.gradle
+++ b/OpenKeychain/build.gradle
@@ -6,10 +6,10 @@ dependencies {
// NOTE: libraries are pinned to a specific build, see below
// from local Android SDK
- compile 'com.android.support:support-v4:22.0.0'
- compile 'com.android.support:appcompat-v7:22.0.0'
- compile 'com.android.support:recyclerview-v7:22.0.0'
- compile 'com.android.support:cardview-v7:22.0.0'
+ compile 'com.android.support:support-v4:22.1.0'
+ compile 'com.android.support:appcompat-v7:22.1.0'
+ compile 'com.android.support:recyclerview-v7:22.1.0'
+ compile 'com.android.support:cardview-v7:22.1.0'
// JCenter etc.
compile 'com.eftimoff:android-patternview:1.0.1@aar'
@@ -17,13 +17,17 @@ dependencies {
compile 'com.journeyapps:zxing-android-integration:2.3.0@aar'
compile 'com.google.zxing:core:3.2.0'
compile 'com.jpardogo.materialtabstrip:library:1.0.9'
- compile 'it.neokree:MaterialNavigationDrawer:1.3.2'
compile 'com.getbase:floatingactionbutton:1.9.0'
compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.0'
compile 'org.ocpsoft.prettytime:prettytime:3.2.7.Final'
compile "com.splitwise:tokenautocomplete:1.3.3@aar"
compile 'se.emilsjolander:stickylistheaders:2.6.0'
compile 'org.sufficientlysecure:html-textview:1.1'
+ compile 'com.mikepenz.materialdrawer:library:2.7.9@aar'
+ compile 'com.mikepenz.iconics:library:0.9.1@aar'
+ compile 'com.mikepenz.iconics:octicons-typeface:2.2.0@aar'
+ compile 'com.mikepenz.iconics:meteocons-typeface:1.1.1@aar'
+ compile 'com.mikepenz.iconics:community-material-typeface:1.0.0@aar'
// libs as submodules
compile project(':extern:openpgp-api-lib')
@@ -42,21 +46,25 @@ dependencies {
// Comment out the libs referenced as git submodules!
dependencyVerification {
verify = [
- 'com.android.support:support-v4:355a11466727e8ba00e239416aec55ac3cd3fb4ffc9d20c4a33373085c050bd1',
- 'com.android.support:appcompat-v7:40114cb756fecffa4a51c5645593cf64509c576594f77e41e801368051115c7b',
- 'com.android.support:recyclerview-v7:859ed80e3761f8fc3126901260b208505120b5678bcf36ad2cfe9c453958b9c7',
- 'com.android.support:cardview-v7:4c03f2acce9925aa4f8845cb8cb37b3772c712b2438ff15f76c9e3d3bc63ead7',
+ 'com.android.support:support-v4:74cb322740317b11a785eee1a94969426fade946123c4ae3f471276adaaaf54b',
+ 'com.android.support:appcompat-v7:6cc7fc2df4be0676f78ecfc5d3cda388e59890d11308811944f54efd84b047b7',
+ 'com.android.support:recyclerview-v7:522d323079a29bcd76173bd9bc7535223b4af3e5eefef9d9287df1f9e54d0c10',
+ 'com.android.support:cardview-v7:8dc99af71fec000baa4470c3907755264f15f816920861bc015b2babdbb49807',
'com.eftimoff:android-patternview:cec80e7265b8d8278b3c55b5fcdf551e4600ac2c8bf60d8dd76adca538af0b1e',
'com.journeyapps:zxing-android-embedded:702a4f58154dbd9baa80f66b6a15410f7a4d403f3e73b66537a8bfb156b4b718',
'com.journeyapps:zxing-android-integration:562737821b6d34c899b6fd2234ce0a8a31e02ff1fd7c59f6211961ce9767c7c8',
'com.google.zxing:core:7fe5a8ff437635a540e56317649937b768b454795ce999ed5f244f83373dee7b',
'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa',
- 'it.neokree:MaterialNavigationDrawer:a1221a410c5f71bf078c5c4768fdf06b402d6006c74f8e7b61199e4edc2aea57',
'com.getbase:floatingactionbutton:052aa2a94e49e5dccc97cb99f2add87e8698b84859f0e3ac181100c0bc7640ca',
'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13',
'com.splitwise:tokenautocomplete:20bee71cc59b3828eb000b684d46ddf738efd56b8fee453a509cd16fda42c8cb',
'se.emilsjolander:stickylistheaders:8c05981ec5725be33f7cee5e68c13f3db49cd5c75f1aaeb04024920b1ef96ad4',
'org.sufficientlysecure:html-textview:ca24b1522be88378634093815ce9ff1b4920c72e7513a045a7846e14069ef988',
+ 'com.mikepenz.materialdrawer:library:3ef80c6e1ca1b29cfcbb27fa7927c02b2246e068c17fe52283703c4897449923',
+ 'com.mikepenz.iconics:library:4698a36ee4c2af765d0a85779c61474d755b90d66a59020105b6760a8a909e9e',
+ 'com.mikepenz.iconics:octicons-typeface:67ed7d456a9ce5f5307b85f955797bfb3dd674e2f6defb31c6b8bbe2ede290be',
+ 'com.mikepenz.iconics:meteocons-typeface:39a8a9e70cd8287cdb119af57a672a41dd09240dba6697f5a0dbda1ccc33298b',
+ 'com.mikepenz.iconics:community-material-typeface:f1c5afee5f0f10d66beb3ed0df977246a02a9c46de4e05d7c0264bcde53b6b7f',
// 'OpenKeychain.extern:openpgp-api-lib:f05a9215cdad3a6597e4c5ece6fcec92b178d218195a3e88d2c0937c48dd9580',
// 'OpenKeychain.extern:openkeychain-api-lib:50f6ebb5452d3fdc7be137ccf857a0ff44d55539fcb7b91baef495766ed7f429',
// 'com.madgag.spongycastle:core:df8fcc028a95ac5ffab3b78c9163f5cfa672e41cd50128ca55d458b6cfbacf4b',
@@ -67,8 +75,7 @@ dependencyVerification {
// 'OpenKeychain.extern.KeybaseLib:Lib:c91cda4a75692d8664644cd17d8ac962ce5bc0e266ea26673a639805f1eccbdf',
// 'OpenKeychain.extern:safeslinger-exchange:d222721bb35408daaab9f46449364b2657112705ee571d7532f81cbeb9c4a73f',
// 'OpenKeychain.extern.snackbar:lib:52357426e5275412e2063bdf6f0e6b957a3ea74da45e0aef35d22d9afc542e23',
- 'com.android.support:support-annotations:ab6b131ab0e1edd165d21fb4c3edadeacbee9539aa166f7f7cbae05b60dc207a',
- 'com.balysv:material-ripple:b2580520bcb5e5d77bd8c42b030317accaf8f88e7e57c46a29c47c8a62d4ff45',
+ 'com.android.support:support-annotations:9c59286413a2bb93e199c73261e58d5af32da7ae0a12cbd075f581a5de1fb446',
]
}
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index f72506144..5280b3047 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -628,6 +628,23 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
</intent-filter>
+ <!-- VIEW from keyserver urls opened in a browser -->
+ <intent-filter android:label="@string/intent_import_key">
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+
+ <data android:scheme="https"/>
+ <data android:scheme="http"/>
+ <!-- if we don't specify a host, pathPattern will be ignored-->
+ <data android:host="*"/>
+ <!-- convention for keyserver paths specified by internet draft
+ draft-shaw-openpgp-hkp-00.txt
+ (http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-3) -->
+ <data android:pathPattern="/pks/lookup.*"/>
+ </intent-filter>
+
<!-- Keychain's own Actions -->
<!-- IMPORT_KEY with files TODO: does this work? -->
<intent-filter android:label="@string/intent_import_key">
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
index 480319081..cb8a53e25 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
@@ -242,7 +242,7 @@ public class HkpKeyserver extends Keyserver {
String encodedQuery;
try {
- encodedQuery = URLEncoder.encode(query, "utf8");
+ encodedQuery = URLEncoder.encode(query, "UTF8");
} catch (UnsupportedEncodingException e) {
return null;
}
@@ -286,7 +286,7 @@ public class HkpKeyserver extends Keyserver {
entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitSize, null));
// group 1 contains the full fingerprint (v4) or the long key id if available
- // see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
+ // see https://bitbucket.org/skskeyserver/sks-keyserver/pull-request/12/fixes-for-machine-readable-indexes/diff
String fingerprintOrKeyId = matcher.group(1).toLowerCase(Locale.ENGLISH);
if (fingerprintOrKeyId.length() > 16) {
entry.setFingerprintHex(fingerprintOrKeyId);
@@ -312,14 +312,13 @@ public class HkpKeyserver extends Keyserver {
String tmp = uidMatcher.group(1).trim();
if (tmp.contains("%")) {
if (tmp.contains("%%")) {
- // This is a fix for issue #683
// The server encodes a percent sign as %%, so it is swapped out with its
// urlencoded counterpart to prevent errors
tmp = tmp.replace("%%", "%25");
}
try {
// converts Strings like "Universit%C3%A4t" to a proper encoding form "Universität".
- tmp = (URLDecoder.decode(tmp, "UTF8"));
+ tmp = URLDecoder.decode(tmp, "UTF8");
} catch (UnsupportedEncodingException ignored) {
// will never happen, because "UTF8" is supported
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java
index 1cd0aaf2f..db62d53c5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java
@@ -123,7 +123,8 @@ public class CreateKeyYubiImportFragment extends Fragment implements NfcListener
});
}
- mListFragment = ImportKeysListFragment.newInstance(null, null, "0x" + mNfcFingerprint, true);
+ mListFragment = ImportKeysListFragment.newInstance(null, null,
+ "0x" + mNfcFingerprint, true, null);
view.findViewById(R.id.button_search).setOnClickListener(new OnClickListener() {
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
index d641f02f9..651b56ab0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
@@ -79,17 +79,18 @@ public abstract class DecryptFragment extends CryptoOperationFragment implements
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mResultLayout = (LinearLayout) view.findViewById(R.id.result_main_layout);
+ // NOTE: These views are inside the activity!
+ mResultLayout = (LinearLayout) getActivity().findViewById(R.id.result_main_layout);
mResultLayout.setVisibility(View.GONE);
- mEncryptionIcon = (ImageView) view.findViewById(R.id.result_encryption_icon);
- mEncryptionText = (TextView) view.findViewById(R.id.result_encryption_text);
- mSignatureIcon = (ImageView) view.findViewById(R.id.result_signature_icon);
- mSignatureText = (TextView) view.findViewById(R.id.result_signature_text);
- mSignatureLayout = view.findViewById(R.id.result_signature_layout);
- mSignatureName = (TextView) view.findViewById(R.id.result_signature_name);
- mSignatureEmail = (TextView) view.findViewById(R.id.result_signature_email);
- mSignatureAction = (TextView) view.findViewById(R.id.result_signature_action);
+ mEncryptionIcon = (ImageView) getActivity().findViewById(R.id.result_encryption_icon);
+ mEncryptionText = (TextView) getActivity().findViewById(R.id.result_encryption_text);
+ mSignatureIcon = (ImageView) getActivity().findViewById(R.id.result_signature_icon);
+ mSignatureText = (TextView) getActivity().findViewById(R.id.result_signature_text);
+ mSignatureLayout = getActivity().findViewById(R.id.result_signature_layout);
+ mSignatureName = (TextView) getActivity().findViewById(R.id.result_signature_name);
+ mSignatureEmail = (TextView) getActivity().findViewById(R.id.result_signature_email);
+ mSignatureAction = (TextView) getActivity().findViewById(R.id.result_signature_action);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java
index 1b9ae917f..6f576a112 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java
@@ -97,9 +97,9 @@ public class DecryptTextFragment extends DecryptFragment {
/**
* Create Intent Chooser but exclude decrypt activites
*/
- private Intent sendWithChooserExcludingEncrypt(String text) {
+ private Intent sendWithChooserExcludingDecrypt(String text) {
Intent prototype = createSendIntent(text);
- String title = getString(R.string.title_share_file);
+ String title = getString(R.string.title_share_message);
// we don't want to decrypt the decrypted, no inception ;)
String[] blacklist = new String[]{
@@ -147,7 +147,7 @@ public class DecryptTextFragment extends DecryptFragment {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.decrypt_share: {
- startActivity(sendWithChooserExcludingEncrypt(mText.getText().toString()));
+ startActivity(sendWithChooserExcludingDecrypt(mText.getText().toString()));
break;
}
case R.id.decrypt_copy: {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
index ccb4a6355..458810541 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
@@ -202,7 +202,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
} catch (IOException e) {
Notify.create(getActivity(),
getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)),
- Notify.Style.ERROR).show();
+ Notify.Style.ERROR).show(this);
return;
}
mSelectedFiles.requestFocus();
@@ -230,7 +230,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
private void encryptClicked(boolean share) {
if (mFilesModels.isEmpty()) {
Notify.create(getActivity(), R.string.error_no_file_selected,
- Notify.Style.ERROR).show();
+ Notify.Style.ERROR).show(this);
return;
}
if (share) {
@@ -247,7 +247,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
} else {
if (mFilesModels.size() > 1) {
Notify.create(getActivity(), R.string.error_multi_not_supported,
- Notify.Style.ERROR).show();
+ Notify.Style.ERROR).show(this);
return;
}
showOutputFileDialog();
@@ -330,7 +330,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
if (mFilesModels.isEmpty()) {
Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR)
- .show();
+ .show(this);
return false;
} else if (mFilesModels.size() > 1 && !mShareAfterEncrypt) {
Log.e(Constants.TAG, "Aborting: mInputUris.size() > 1 && !mShareAfterEncrypt");
@@ -347,12 +347,12 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
if (mPassphrase == null) {
Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR)
- .show();
+ .show(this);
return false;
}
if (mPassphrase.isEmpty()) {
Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
- .show();
+ .show(this);
return false;
}
@@ -365,7 +365,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment {
// Files must be encrypted, only text can be signed-only right now
if (!gotEncryptionKeys) {
Notify.create(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR)
- .show();
+ .show(this);
return false;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
index 03ab48e23..dd6dd6594 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
@@ -98,23 +98,20 @@ public class EncryptTextActivity extends BaseActivity implements
// handle like normal text encryption, override action and extras to later
// executeServiceMethod ACTION_ENCRYPT_TEXT in main actions
extras.putString(EXTRA_TEXT, sharedText);
- action = ACTION_ENCRYPT_TEXT;
}
}
}
String textData = extras.getString(EXTRA_TEXT);
- if (ACTION_ENCRYPT_TEXT.equals(action) && textData == null) {
- Log.e(Constants.TAG, "Include the extra 'text' in your Intent!");
- return;
+ if (textData == null) {
+ textData = "";
}
// preselect keys given by intent
long mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID);
long[] mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS);
-
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
index b37a2ca79..3f9147cc4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
@@ -288,9 +288,9 @@ public class EncryptTextFragment extends CryptoOperationFragment {
}
protected boolean inputIsValid() {
- if (mMessage == null) {
- Notify.create(getActivity(), R.string.error_message, Notify.Style.ERROR)
- .show();
+ if (mMessage == null || mMessage.isEmpty()) {
+ Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR)
+ .show(this);
return false;
}
@@ -299,12 +299,12 @@ public class EncryptTextFragment extends CryptoOperationFragment {
if (mSymmetricPassphrase == null) {
Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR)
- .show();
+ .show(this);
return false;
}
if (mSymmetricPassphrase.isEmpty()) {
Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
- .show();
+ .show(this);
return false;
}
@@ -316,7 +316,7 @@ public class EncryptTextFragment extends CryptoOperationFragment {
if (!gotEncryptionKeys && mSigningKeyId == 0) {
Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR)
- .show();
+ .show(this);
return false;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 7fe5be793..5d9950db6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -39,6 +39,7 @@ import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
import org.sufficientlysecure.keychain.service.CloudImportService;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
@@ -62,6 +63,8 @@ public class ImportKeysActivity extends BaseNfcActivity {
// Actions for internal use only:
public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_FILE";
+ public static final String ACTION_SEARCH_KEYSERVER_FROM_URL = Constants.INTENT_PREFIX
+ + "SEARCH_KEYSERVER_FROM_URL";
public static final String EXTRA_RESULT = "result";
// only used by ACTION_IMPORT_KEY
@@ -112,15 +115,19 @@ public class ImportKeysActivity extends BaseNfcActivity {
}
if (action == null) {
- startCloudFragment(savedInstanceState, null, false);
- startListFragment(savedInstanceState, null, null, null);
+ startCloudFragment(savedInstanceState, null, false, null);
+ startListFragment(savedInstanceState, null, null, null, null);
return;
}
if (Intent.ACTION_VIEW.equals(action)) {
- // Android's Action when opening file associated to Keychain (see AndroidManifest.xml)
- // delegate action to ACTION_IMPORT_KEY
- action = ACTION_IMPORT_KEY;
+ if (scheme.equals("http") || scheme.equals("https")) {
+ action = ACTION_SEARCH_KEYSERVER_FROM_URL;
+ } else {
+ // Android's Action when opening file associated to Keychain (see AndroidManifest.xml)
+ // delegate action to ACTION_IMPORT_KEY
+ action = ACTION_IMPORT_KEY;
+ }
}
switch (action) {
@@ -130,12 +137,12 @@ public class ImportKeysActivity extends BaseNfcActivity {
if (dataUri != null) {
// action: directly load data
- startListFragment(savedInstanceState, null, dataUri, null);
+ startListFragment(savedInstanceState, null, dataUri, null, null);
} else if (extras.containsKey(EXTRA_KEY_BYTES)) {
byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES);
// action: directly load data
- startListFragment(savedInstanceState, importData, null, null);
+ startListFragment(savedInstanceState, importData, null, null, null);
}
break;
}
@@ -162,10 +169,10 @@ public class ImportKeysActivity extends BaseNfcActivity {
if (query != null && query.length() > 0) {
// display keyserver fragment with query
- startCloudFragment(savedInstanceState, query, false);
+ startCloudFragment(savedInstanceState, query, false, null);
// action: search immediately
- startListFragment(savedInstanceState, null, null, query);
+ startListFragment(savedInstanceState, null, null, query, null);
} else {
Log.e(Constants.TAG, "Query is empty!");
return;
@@ -181,10 +188,10 @@ public class ImportKeysActivity extends BaseNfcActivity {
String query = "0x" + fingerprint;
// display keyserver fragment with query
- startCloudFragment(savedInstanceState, query, true);
+ startCloudFragment(savedInstanceState, query, true, null);
// action: search immediately
- startListFragment(savedInstanceState, null, null, query);
+ startListFragment(savedInstanceState, null, null, query, null);
}
} else {
Log.e(Constants.TAG,
@@ -200,7 +207,29 @@ public class ImportKeysActivity extends BaseNfcActivity {
startFileFragment(savedInstanceState);
// no immediate actions!
- startListFragment(savedInstanceState, null, null, null);
+ startListFragment(savedInstanceState, null, null, null, null);
+ break;
+ }
+ case ACTION_SEARCH_KEYSERVER_FROM_URL: {
+ // need to process URL to get search query and keyserver authority
+ String query = dataUri.getQueryParameter("search");
+ String keyserver = dataUri.getAuthority();
+ // if query not specified, we still allow users to search the keyserver in the link
+ if (query == null) {
+ Notify.create(this, R.string.import_url_warn_no_search_parameter, Notify.LENGTH_INDEFINITE,
+ Notify.Style.WARN).show(mTopFragment);
+ // we just set the keyserver
+ startCloudFragment(savedInstanceState, null, false, keyserver);
+ // it's not necessary to set the keyserver for ImportKeysListFragment since
+ // it'll be taken care of by ImportKeysCloudFragment when the user clicks
+ // the search button
+ startListFragment(savedInstanceState, null, null, null, null);
+ } else {
+ // we allow our users to edit the query if they wish
+ startCloudFragment(savedInstanceState, query, false, keyserver);
+ // search immediately
+ startListFragment(savedInstanceState, null, null, query, keyserver);
+ }
break;
}
case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: {
@@ -208,18 +237,31 @@ public class ImportKeysActivity extends BaseNfcActivity {
startFileFragment(savedInstanceState);
// no immediate actions!
- startListFragment(savedInstanceState, null, null, null);
+ startListFragment(savedInstanceState, null, null, null, null);
break;
}
default: {
- startCloudFragment(savedInstanceState, null, false);
- startListFragment(savedInstanceState, null, null, null);
+ startCloudFragment(savedInstanceState, null, false, null);
+ startListFragment(savedInstanceState, null, null, null, null);
break;
}
}
}
- private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, String serverQuery) {
+
+ /**
+ * if the fragment is started with non-null bytes/dataUri/serverQuery, it will immediately
+ * load content
+ *
+ * @param savedInstanceState
+ * @param bytes bytes containing list of keyrings to import
+ * @param dataUri uri to file to import keyrings from
+ * @param serverQuery query to search for on the keyserver
+ * @param keyserver keyserver authority to search on. If null will use keyserver from
+ * user preferences
+ */
+ private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri,
+ String serverQuery, String keyserver) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
@@ -227,8 +269,8 @@ public class ImportKeysActivity extends BaseNfcActivity {
return;
}
- // Create an instance of the fragment
- mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery);
+ mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery, false,
+ keyserver);
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
@@ -259,7 +301,18 @@ public class ImportKeysActivity extends BaseNfcActivity {
getSupportFragmentManager().executePendingTransactions();
}
- private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit) {
+ /**
+ * loads the CloudFragment, which consists of the search bar, search button and settings icon
+ * visually.
+ *
+ * @param savedInstanceState
+ * @param query search query
+ * @param disableQueryEdit if true, user will not be able to edit the search query
+ * @param keyserver keyserver authority to use for search, if null will use keyserver
+ * specified in user preferences
+ */
+
+ private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit, String keyserver) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
@@ -268,7 +321,7 @@ public class ImportKeysActivity extends BaseNfcActivity {
}
// Create an instance of the fragment
- mTopFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit);
+ mTopFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit, keyserver);
// Add the fragment to the 'fragment_container' FrameLayout
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java
index 91ca93c36..1cd5c24f3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java
@@ -45,6 +45,7 @@ import java.util.List;
public class ImportKeysCloudFragment extends Fragment {
public static final String ARG_QUERY = "query";
public static final String ARG_DISABLE_QUERY_EDIT = "disable_query_edit";
+ public static final String ARG_KEYSERVER = "keyserver";
private ImportKeysActivity mImportActivity;
@@ -54,13 +55,20 @@ public class ImportKeysCloudFragment extends Fragment {
/**
* Creates new instance of this fragment
+ *
+ * @param query query to search for
+ * @param disableQueryEdit if true, user cannot edit query
+ * @param keyserver specified keyserver authority to use. If null, will use keyserver
+ * specified in user preferences
*/
- public static ImportKeysCloudFragment newInstance(String query, boolean disableQueryEdit) {
+ public static ImportKeysCloudFragment newInstance(String query, boolean disableQueryEdit,
+ String keyserver) {
ImportKeysCloudFragment frag = new ImportKeysCloudFragment();
Bundle args = new Bundle();
args.putString(ARG_QUERY, query);
args.putBoolean(ARG_DISABLE_QUERY_EDIT, disableQueryEdit);
+ args.putString(ARG_KEYSERVER, keyserver);
frag.setArguments(args);
@@ -151,8 +159,17 @@ public class ImportKeysCloudFragment extends Fragment {
}
private void search(String query) {
- Preferences prefs = Preferences.getPreferences(getActivity());
- mImportActivity.loadCallback(new ImportKeysListFragment.CloudLoaderState(query, prefs.getCloudSearchPrefs()));
+ Preferences.CloudSearchPrefs cloudSearchPrefs;
+ String explicitKeyserver = getArguments().getString(ARG_KEYSERVER);
+ // no explicit keyserver passed
+ if (explicitKeyserver == null) {
+ cloudSearchPrefs = Preferences.getPreferences(getActivity()).getCloudSearchPrefs();
+ } else {
+ // assume we are also meant to search keybase.io
+ cloudSearchPrefs = new Preferences.CloudSearchPrefs(true, true, explicitKeyserver);
+ }
+ mImportActivity.loadCallback(
+ new ImportKeysListFragment.CloudLoaderState(query, cloudSearchPrefs));
toggleKeyboard(false);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
index b9fdbea5c..bf7e41045 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
@@ -58,6 +58,7 @@ public class ImportKeysListFragment extends ListFragment implements
private static final String ARG_BYTES = "bytes";
public static final String ARG_SERVER_QUERY = "query";
public static final String ARG_NON_INTERACTIVE = "non_interactive";
+ public static final String ARG_KEYSERVER_URL = "keyserver_url";
private Activity mActivity;
private ImportKeysAdapter mAdapter;
@@ -78,7 +79,8 @@ public class ImportKeysListFragment extends ListFragment implements
return mAdapter.getData();
}
- /** Returns an Iterator (with size) of the selected data items.
+ /**
+ * Returns an Iterator (with size) of the selected data items.
* This iterator is sort of a tradeoff, it's slightly more complex than an
* ArrayList would have been, but we save some memory by just returning
* relevant elements on demand.
@@ -121,12 +123,36 @@ public class ImportKeysListFragment extends ListFragment implements
}
- public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery) {
- return newInstance(bytes, dataUri, serverQuery, false);
+ /**
+ * Creates an interactive ImportKeyListFragment which reads keyrings from bytes, or file specified
+ * by dataUri, or searches a keyserver for serverQuery, if parameter is not null, in that order
+ *
+ * @param bytes byte data containing list of keyrings to be imported
+ * @param dataUri file from which keyrings are to be imported
+ * @param serverQuery query to search for on keyserver
+ * @param keyserver if not null, will perform search on specified keyserver. Else, uses
+ * keyserver specified in user preferences
+ * @return fragment with arguments set based on passed parameters
+ */
+ public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery,
+ String keyserver) {
+ return newInstance(bytes, dataUri, serverQuery, false, keyserver);
}
- public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri,
- String serverQuery, boolean nonInteractive) {
+ /**
+ * Visually consists of a list of keyrings with checkboxes to specify which are to be imported
+ * Can immediately load keyrings specified by any of its parameters
+ *
+ * @param bytes byte data containing list of keyrings to be imported
+ * @param dataUri file from which keyrings are to be imported
+ * @param serverQuery query to search for on keyserver
+ * @param nonInteractive if true, users will not be able to check/uncheck items in the list
+ * @param keyserver if set, will perform search on specified keyserver. If null, falls back
+ * to keyserver specified in user preferences
+ * @return fragment with arguments set based on passed parameters
+ */
+ public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery,
+ boolean nonInteractive, String keyserver) {
ImportKeysListFragment frag = new ImportKeysListFragment();
Bundle args = new Bundle();
@@ -134,6 +160,7 @@ public class ImportKeysListFragment extends ListFragment implements
args.putParcelable(ARG_DATA_URI, dataUri);
args.putString(ARG_SERVER_QUERY, serverQuery);
args.putBoolean(ARG_NON_INTERACTIVE, nonInteractive);
+ args.putString(ARG_KEYSERVER_URL, keyserver);
frag.setArguments(args);
@@ -180,16 +207,23 @@ public class ImportKeysListFragment extends ListFragment implements
setListAdapter(mAdapter);
Bundle args = getArguments();
- Uri dataUri = args.containsKey(ARG_DATA_URI) ? args.<Uri>getParcelable(ARG_DATA_URI) : null;
- byte[] bytes = args.containsKey(ARG_BYTES) ? args.getByteArray(ARG_BYTES) : null;
- String query = args.containsKey(ARG_SERVER_QUERY) ? args.getString(ARG_SERVER_QUERY) : null;
- mNonInteractive = args.containsKey(ARG_NON_INTERACTIVE) ? args.getBoolean(ARG_NON_INTERACTIVE) : false;
+ Uri dataUri = args.getParcelable(ARG_DATA_URI);
+ byte[] bytes = args.getByteArray(ARG_BYTES);
+ String query = args.getString(ARG_SERVER_QUERY);
+ String keyserver = args.getString(ARG_KEYSERVER_URL);
+ mNonInteractive = args.getBoolean(ARG_NON_INTERACTIVE, false);
if (dataUri != null || bytes != null) {
mLoaderState = new BytesLoaderState(bytes, dataUri);
} else if (query != null) {
- Preferences prefs = Preferences.getPreferences(getActivity());
- mLoaderState = new CloudLoaderState(query, prefs.getCloudSearchPrefs());
+ Preferences.CloudSearchPrefs cloudSearchPrefs;
+ if (keyserver == null) {
+ cloudSearchPrefs = Preferences.getPreferences(getActivity()).getCloudSearchPrefs();
+ } else {
+ cloudSearchPrefs = new Preferences.CloudSearchPrefs(true, true, keyserver);
+ }
+
+ mLoaderState = new CloudLoaderState(query, cloudSearchPrefs);
}
getListView().setOnTouchListener(new OnTouchListener() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
index b9f1bf870..29f2511a0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
@@ -58,13 +58,12 @@ import java.util.Locale;
public class ImportKeysProxyActivity extends FragmentActivity {
public static final String ACTION_QR_CODE_API = OpenKeychainIntents.IMPORT_KEY_FROM_QR_CODE;
+ // implies activity returns scanned fingerprint as extra and does not import
public static final String ACTION_SCAN_WITH_RESULT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_WITH_RESULT";
public static final String ACTION_SCAN_IMPORT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_IMPORT";
public static final String EXTRA_FINGERPRINT = "fingerprint";
- boolean returnResult;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -82,18 +81,9 @@ public class ImportKeysProxyActivity extends FragmentActivity {
if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) {
// Scanning a fingerprint directly with Barcode Scanner, thus we already have scanned
- returnResult = false;
processScannedContent(dataUri);
- } else if (ACTION_SCAN_IMPORT.equals(action) || ACTION_QR_CODE_API.equals(action)) {
- returnResult = false;
- IntentIntegrator integrator = new IntentIntegrator(this);
- integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
- .setPrompt(getString(R.string.import_qr_code_text))
- .setResultDisplayDuration(0);
- integrator.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- integrator.initiateScan();
- } else if (ACTION_SCAN_WITH_RESULT.equals(action)) {
- returnResult = true;
+ } else if (ACTION_SCAN_WITH_RESULT.equals(action)
+ || ACTION_SCAN_IMPORT.equals(action) || ACTION_QR_CODE_API.equals(action)) {
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
.setPrompt(getString(R.string.import_qr_code_text))
@@ -103,7 +93,6 @@ public class ImportKeysProxyActivity extends FragmentActivity {
} else if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
// Check to see if the Activity started due to an Android Beam
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- returnResult = false;
handleActionNdefDiscovered(getIntent());
} else {
Log.e(Constants.TAG, "Android Beam not supported by Android < 4.1");
@@ -147,69 +136,63 @@ public class ImportKeysProxyActivity extends FragmentActivity {
}
private void processScannedContent(Uri uri) {
+ String action = getIntent().getAction();
Log.d(Constants.TAG, "scanned: " + uri);
- String fingerprint = null;
-
// example: openpgp4fpr:73EE2314F65FA92EC2390D3A718C070100012282
if (uri != null && uri.getScheme() != null && uri.getScheme().toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) {
- fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH);
- }
+ String fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH);
- if (fingerprint == null) {
+ if (ACTION_SCAN_WITH_RESULT.equals(action)) {
+ Intent result = new Intent();
+ result.putExtra(EXTRA_FINGERPRINT, fingerprint);
+ setResult(RESULT_OK, result);
+ finish();
+ } else {
+ importKeys(fingerprint);
+ }
+ } else {
SingletonResult result = new SingletonResult(
SingletonResult.RESULT_ERROR, OperationResult.LogType.MSG_WRONG_QR_CODE);
Intent intent = new Intent();
intent.putExtra(SingletonResult.EXTRA_RESULT, result);
returnResult(intent);
- return;
- }
-
- if (returnResult) {
- Intent result = new Intent();
- result.putExtra(EXTRA_FINGERPRINT, fingerprint);
- setResult(RESULT_OK, result);
- finish();
- } else {
- importKeys(fingerprint);
}
}
public void returnResult(Intent data) {
- if (returnResult) {
- setResult(RESULT_OK, data);
- finish();
- } else {
+ String action = getIntent().getAction();
+
+ if (ACTION_QR_CODE_API.equals(action)) {
// display last log message but as Toast for calls from outside OpenKeychain
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
String str = getString(result.getLog().getLast().mType.getMsgId());
Toast.makeText(this, str, Toast.LENGTH_LONG).show();
finish();
+ } else {
+ setResult(RESULT_OK, data);
+ finish();
}
}
public void importKeys(byte[] keyringData) {
-
ParcelableKeyRing keyEntry = new ParcelableKeyRing(keyringData);
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
selectedEntries.add(keyEntry);
startImportService(selectedEntries);
-
}
public void importKeys(String fingerprint) {
-
ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
selectedEntries.add(keyEntry);
startImportService(selectedEntries);
-
}
- private void startImportService (ArrayList<ParcelableKeyRing> keyRings) {
+ private void startImportService(ArrayList<ParcelableKeyRing> keyRings) {
// Message is received after importing is done in KeychainIntentService
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(
@@ -282,7 +265,6 @@ public class ImportKeysProxyActivity extends FragmentActivity {
// start service with intent
startService(intent);
-
}
/**
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index 36ed99f69..edaea539b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -682,17 +682,16 @@ public class KeyListFragment extends LoaderFragment
}
private void showMultiExportDialog(long[] masterKeyIds) {
- mIdsForRepeatAskPassphrase = new ArrayList<Long>();
- for(long id: masterKeyIds) {
+ mIdsForRepeatAskPassphrase = new ArrayList<>();
+ for (long id : masterKeyIds) {
try {
if (PassphraseCacheService.getCachedPassphrase(
getActivity(), id, id) == null) {
- mIdsForRepeatAskPassphrase.add(Long.valueOf(id));
+ mIdsForRepeatAskPassphrase.add(id);
}
} catch (PassphraseCacheService.KeyNotFoundException e) {
// This happens when the master key is stripped
// and ignore this key.
- continue;
}
}
mIndex = 0;
@@ -701,8 +700,8 @@ public class KeyListFragment extends LoaderFragment
return;
}
long[] idsForMultiExport = new long[mIdsForRepeatAskPassphrase.size()];
- for(int i=0; i<mIdsForRepeatAskPassphrase.size(); ++i) {
- idsForMultiExport[i] = mIdsForRepeatAskPassphrase.get(i).longValue();
+ for (int i = 0; i < mIdsForRepeatAskPassphrase.size(); ++i) {
+ idsForMultiExport[i] = mIdsForRepeatAskPassphrase.get(i);
}
mExportHelper.showExportKeysDialog(idsForMultiExport,
Constants.Path.APP_DIR_FILE,
@@ -711,7 +710,7 @@ public class KeyListFragment extends LoaderFragment
private void startPassphraseActivity() {
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
- long masterKeyId = mIdsForRepeatAskPassphrase.get(mIndex++).longValue();
+ long masterKeyId = mIdsForRepeatAskPassphrase.get(mIndex++);
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, masterKeyId);
startActivityForResult(intent, REQUEST_REPEAT_PASSPHRASE);
}
@@ -719,7 +718,7 @@ public class KeyListFragment extends LoaderFragment
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
- if(resultCode != Activity.RESULT_OK) {
+ if (resultCode != Activity.RESULT_OK) {
return;
}
if (mIndex < mIdsForRepeatAskPassphrase.size()) {
@@ -727,8 +726,8 @@ public class KeyListFragment extends LoaderFragment
return;
}
long[] idsForMultiExport = new long[mIdsForRepeatAskPassphrase.size()];
- for(int i=0; i<mIdsForRepeatAskPassphrase.size(); ++i) {
- idsForMultiExport[i] = mIdsForRepeatAskPassphrase.get(i).longValue();
+ for (int i = 0; i < mIdsForRepeatAskPassphrase.size(); ++i) {
+ idsForMultiExport[i] = mIdsForRepeatAskPassphrase.get(i);
}
mExportHelper.showExportKeysDialog(idsForMultiExport,
Constants.Path.APP_DIR_FILE,
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
index 5fa3edba4..05cf64092 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Kai Jiang <jiangkai@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,36 +21,98 @@ package org.sufficientlysecure.keychain.ui;
import android.content.Intent;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+import android.widget.AdapterView;
+
+import com.mikepenz.community_material_typeface_library.CommunityMaterial;
+import com.mikepenz.google_material_typeface_library.GoogleMaterial;
+import com.mikepenz.iconics.typeface.FontAwesome;
+import com.mikepenz.materialdrawer.Drawer;
+import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
+import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.remote.ui.AppsListFragment;
-import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.FabContainer;
+import org.sufficientlysecure.keychain.util.Preferences;
-import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer;
+public class MainActivity extends AppCompatActivity implements FabContainer {
-public class MainActivity extends MaterialNavigationDrawer implements FabContainer {
+ public Drawer.Result result;
- @Override
- public void init(Bundle savedInstanceState) {
- // don't open drawer on first run
- disableLearningPattern();
+ private KeyListFragment mKeyListFragment ;
+ private AppsListFragment mAppsListFragment;
+ private EncryptDecryptOverviewFragment mEncryptDecryptOverviewFragment;
+ private Fragment mLastUsedFragment;
+ private Toolbar mToolbar;
-// addMultiPaneSupport();
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main_activity);
- // set the header image
- // create and set the header
- setDrawerHeaderImage(R.drawable.drawer_header);
+ //initialize FragmentLayout with KeyListFragment at first
+ Fragment mainFragment = new KeyListFragment();
+ FragmentManager fm = getSupportFragmentManager();
+ FragmentTransaction transaction = fm.beginTransaction();
+ transaction.replace(R.id.main_fragment_container, mainFragment);
+ transaction.commit();
- // create sections
- addSection(newSection(getString(R.string.nav_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment()));
- addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment()));
- addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment()));
+ mToolbar = (Toolbar) findViewById(R.id.activity_main_toolbar);
+ mToolbar.setTitle(R.string.app_name);
+ setSupportActionBar(mToolbar);
- // create bottom section
- addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class)));
- addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class)));
+ result = new Drawer()
+ .withActivity(this)
+ .withHeader(R.layout.main_drawer_header)
+ .withToolbar(mToolbar)
+ .addDrawerItems(
+ new PrimaryDrawerItem().withName(R.string.nav_keys).withIcon(CommunityMaterial.Icon.cmd_key).withIdentifier(1).withCheckable(false),
+ new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock).withIdentifier(2).withCheckable(false),
+ new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps).withIdentifier(3).withCheckable(false)
+ )
+ .addStickyDrawerItems(
+ // display and stick on bottom of drawer
+ new PrimaryDrawerItem().withName(R.string.menu_preferences).withIcon(GoogleMaterial.Icon.gmd_settings).withIdentifier(4).withCheckable(false),
+ new PrimaryDrawerItem().withName(R.string.menu_help).withIcon(CommunityMaterial.Icon.cmd_help_circle).withIdentifier(5).withCheckable(false)
+ )
+ .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id, IDrawerItem drawerItem) {
+ if (drawerItem != null) {
+ Intent intent = null;
+ switch(drawerItem.getIdentifier()) {
+ case 1:
+ onKeysSelected();
+ break;
+ case 2:
+ onEnDecryptSelected();
+ break;
+ case 3:
+ onAppsSelected();
+ break;
+ case 4:
+ intent = new Intent(MainActivity.this, SettingsActivity.class);
+ break;
+ case 5:
+ intent = new Intent(MainActivity.this, HelpActivity.class);
+ break;
+ }
+ if (intent != null) {
+ MainActivity.this.startActivity(intent);
+ }
+ }
+ }
+ })
+ .withSelectedItem(-1)
+ .withSavedInstance(savedInstanceState)
+ .build();
// if this is the first time show first time activity
Preferences prefs = Preferences.getPreferences(this);
@@ -69,9 +132,83 @@ public class MainActivity extends MaterialNavigationDrawer implements FabContain
}
}
+ private void clearFragments() {
+ mKeyListFragment = null;
+ mAppsListFragment = null;
+ mEncryptDecryptOverviewFragment = null;
+
+ getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ }
+
+ private void setFragment(Fragment fragment) {
+ setFragment(fragment, true);
+ }
+
+ private void setFragment(Fragment fragment, boolean addToBackStack) {
+ this.mLastUsedFragment = fragment;
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.main_fragment_container, fragment);
+ if (addToBackStack) {
+ ft.addToBackStack(null);
+ }
+ ft.commit();
+ }
+
+ private boolean onKeysSelected() {
+ mToolbar.setTitle(R.string.app_name);
+ clearFragments();
+
+ if (mKeyListFragment == null) {
+ mKeyListFragment = new KeyListFragment();
+ }
+
+ setFragment(mKeyListFragment, false);
+ return true;
+ }
+
+ private boolean onEnDecryptSelected() {
+ mToolbar.setTitle(R.string.nav_encrypt_decrypt);
+ clearFragments();
+ if (mEncryptDecryptOverviewFragment == null) {
+ mEncryptDecryptOverviewFragment = new EncryptDecryptOverviewFragment();
+ }
+
+ setFragment(mEncryptDecryptOverviewFragment);
+ return true;
+ }
+
+ private boolean onAppsSelected() {
+ mToolbar.setTitle(R.string.nav_apps);
+ clearFragments();
+ if (mAppsListFragment == null) {
+ mAppsListFragment = new AppsListFragment();
+ }
+
+ setFragment(mAppsListFragment);
+ return true;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ //add the values which need to be saved from the drawer to the bundle
+ outState = result.saveInstanceState(outState);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ public void onBackPressed(){
+ //handle the back press :D close the drawer first and if the drawer is closed close the activity
+ if (result != null && result.isDrawerOpen()) {
+ result.closeDrawer();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
@Override
public void fabMoveUp(int height) {
- Object fragment = getCurrentSection().getTargetFragment();
+ Object fragment = getSupportFragmentManager()
+ .findFragmentById(R.id.main_fragment_container);
if (fragment instanceof FabContainer) {
((FabContainer) fragment).fabMoveUp(height);
}
@@ -79,7 +216,8 @@ public class MainActivity extends MaterialNavigationDrawer implements FabContain
@Override
public void fabRestorePosition() {
- Object fragment = getCurrentSection().getTargetFragment();
+ Object fragment = getSupportFragmentManager()
+ .findFragmentById(R.id.main_fragment_container);
if (fragment instanceof FabContainer) {
((FabContainer) fragment).fabRestorePosition();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java
index 9f2e46b38..8f025c769 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java
@@ -20,6 +20,9 @@ package org.sufficientlysecure.keychain.ui;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -28,6 +31,8 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
+import org.sufficientlysecure.keychain.ui.dialog.AddKeyserverDialogFragment;
+import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.widget.Editor;
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor;
@@ -95,7 +100,7 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi
Intent intent = getIntent();
String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS);
makeServerList(servers);
- }
+ }
@Override
protected void initLayout() {
@@ -124,10 +129,63 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi
}
+ // button to add keyserver clicked
public void onClick(View v) {
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ Bundle data = message.getData();
+ switch (message.what) {
+ case AddKeyserverDialogFragment.MESSAGE_OKAY: {
+ boolean verified = data.getBoolean(AddKeyserverDialogFragment.MESSAGE_VERIFIED);
+ if (verified) {
+ Notify.create(SettingsKeyServerActivity.this,
+ R.string.add_keyserver_verified, Notify.Style.OK).show();
+ } else {
+ Notify.create(SettingsKeyServerActivity.this,
+ R.string.add_keyserver_without_verification,
+ Notify.Style.WARN).show();
+ }
+ String keyserver = data.getString(AddKeyserverDialogFragment.MESSAGE_KEYSERVER);
+ addKeyserver(keyserver);
+ break;
+ }
+ case AddKeyserverDialogFragment.MESSAGE_VERIFICATION_FAILED: {
+ AddKeyserverDialogFragment.FailureReason failureReason =
+ (AddKeyserverDialogFragment.FailureReason) data.getSerializable(
+ AddKeyserverDialogFragment.MESSAGE_FAILURE_REASON);
+ switch (failureReason) {
+ case CONNECTION_FAILED: {
+ Notify.create(SettingsKeyServerActivity.this,
+ R.string.add_keyserver_connection_failed,
+ Notify.Style.ERROR).show();
+ break;
+ }
+ case INVALID_URL: {
+ Notify.create(SettingsKeyServerActivity.this,
+ R.string.add_keyserver_invalid_url,
+ Notify.Style.ERROR).show();
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+ AddKeyserverDialogFragment dialogFragment = AddKeyserverDialogFragment
+ .newInstance(messenger, R.string.add_keyserver_dialog_title);
+ dialogFragment.show(getSupportFragmentManager(), "addKeyserverDialog");
+ }
+
+ public void addKeyserver(String keyserverUrl) {
KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor,
mEditors, false);
view.setEditorListener(this);
+ view.setValue(keyserverUrl);
mEditors.addView(view);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
index 5447c5f96..139512ba9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
@@ -82,12 +82,12 @@ public class ImportKeysListLoader
@Override
protected void onStartLoading() {
- forceLoad();
+ super.forceLoad();
}
@Override
protected void onStopLoading() {
- cancelLoad();
+ super.cancelLoad();
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java
index 963e77fe9..7b911da96 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java
@@ -21,7 +21,7 @@ import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
import java.util.ArrayList;
@@ -41,7 +41,7 @@ public class PagerTabStripAdapter extends FragmentPagerAdapter {
}
}
- public PagerTabStripAdapter(ActionBarActivity activity) {
+ public PagerTabStripAdapter(AppCompatActivity activity) {
super(activity.getSupportFragmentManager());
mActivity = activity;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
index 44afed351..a1f00599c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
@@ -24,7 +24,7 @@ import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
import java.util.ArrayList;
@@ -45,7 +45,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
}
}
- public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
+ public TabsAdapter(AppCompatActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java
index 07d2ef8c0..0e752881f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java
@@ -20,7 +20,7 @@ package org.sufficientlysecure.keychain.ui.base;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -33,7 +33,7 @@ import org.sufficientlysecure.keychain.R;
/**
* Setups Toolbar
*/
-public abstract class BaseActivity extends ActionBarActivity {
+public abstract class BaseActivity extends AppCompatActivity {
protected Toolbar mToolbar;
protected View mStatusBar;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
index 95c1690b1..1d09b281f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
@@ -57,6 +57,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
public static final int REQUEST_CODE_PASSPHRASE = 1;
protected Passphrase mPin;
+ protected boolean mPw1ValidForMultipleSignatures;
+ protected boolean mPw1ValidatedForSignature;
+ protected boolean mPw1ValidatedForDecrypt; // Mode 82 does other things; consider renaming?
private NfcAdapter mNfcAdapter;
private IsoDep mIsoDep;
@@ -197,10 +200,15 @@ public abstract class BaseNfcActivity extends BaseActivity {
+ "06" // Lc (number of bytes)
+ "D27600012401" // Data (6 bytes)
+ "00"; // Le
- if ( ! nfcCommunicate(opening).equals(accepted)) { // activate connection
+ if ( ! nfcCommunicate(opening).endsWith(accepted)) { // activate connection
throw new IOException("Initialization failed!");
}
+ byte[] pwStatusBytes = nfcGetPwStatusBytes();
+ mPw1ValidForMultipleSignatures = (pwStatusBytes[0] == 1);
+ mPw1ValidatedForSignature = false;
+ mPw1ValidatedForDecrypt = false;
+
onNfcPerform();
mIsoDep.close();
@@ -278,6 +286,15 @@ public abstract class BaseNfcActivity extends BaseActivity {
return fptlv.mV;
}
+ /** Return the PW Status Bytes from the card. This is a simple DO; no TLV decoding needed.
+ *
+ * @return Seven bytes in fixed format, plus 0x9000 status word at the end.
+ */
+ public byte[] nfcGetPwStatusBytes() throws IOException {
+ String data = "00CA00C400";
+ return mIsoDep.transceive(Hex.decode(data));
+ }
+
/** Return the fingerprint from application specific data stored on tag, or
* null if it doesn't exist.
*
@@ -316,7 +333,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
* @return a big integer representing the MPI for the given hash
*/
public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException {
- nfcVerifyPIN(0x81); // (Verify PW1 with mode 81 for signing)
+ if (!mPw1ValidatedForSignature) {
+ nfcVerifyPIN(0x81); // (Verify PW1 with mode 81 for signing)
+ }
// dsi, including Lc
String dsi;
@@ -391,6 +410,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
Log.d(Constants.TAG, "final response:" + status);
+ if (!mPw1ValidForMultipleSignatures) {
+ mPw1ValidatedForSignature = false;
+ }
+
if ( ! "9000".equals(status)) {
throw new IOException("Bad NFC response code: " + status);
}
@@ -410,7 +433,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
* @return the decoded session key
*/
public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException {
- nfcVerifyPIN(0x82); // (Verify PW1 with mode 82 for decryption)
+ if (!mPw1ValidatedForDecrypt) {
+ nfcVerifyPIN(0x82); // (Verify PW1 with mode 82 for decryption)
+ }
String firstApdu = "102a8086fe";
String secondApdu = "002a808603";
@@ -458,6 +483,12 @@ public abstract class BaseNfcActivity extends BaseActivity {
handlePinError();
throw new IOException("Bad PIN!");
}
+
+ if (mode == 0x81) {
+ mPw1ValidatedForSignature = true;
+ } else if (mode == 0x82) {
+ mPw1ValidatedForDecrypt = true;
+ }
}
}
@@ -476,6 +507,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
*/
public void enableNfcForegroundDispatch() {
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
+ if (mNfcAdapter == null) {
+ return;
+ }
Intent nfcI = new Intent(this, getClass())
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT);
@@ -497,6 +531,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
* Disable foreground dispatch in onPause!
*/
public void disableNfcForegroundDispatch() {
+ if (mNfcAdapter == null) {
+ return;
+ }
mNfcAdapter.disableForegroundDispatch(this);
Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java
new file mode 100644
index 000000000..cbef5950f
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui.dialog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.support.v4.app.DialogFragment;
+import android.test.suitebuilder.TestSuiteBuilder;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.TlsHelper;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+
+public class AddKeyserverDialogFragment extends DialogFragment implements OnEditorActionListener {
+ private static final String ARG_MESSENGER = "messenger";
+ private static final String ARG_TITLE = "title";
+
+ public static final int MESSAGE_OKAY = 1;
+ public static final int MESSAGE_VERIFICATION_FAILED = 2;
+
+ public static final String MESSAGE_KEYSERVER = "new_keyserver";
+ public static final String MESSAGE_VERIFIED = "verified";
+ public static final String MESSAGE_FAILURE_REASON = "failure_reason";
+
+ private Messenger mMessenger;
+ private EditText mKeyserverEditText;
+ private CheckBox mVerifyKeyserverCheckBox;
+
+ public static enum FailureReason {
+ INVALID_URL,
+ CONNECTION_FAILED
+ }
+
+ ;
+
+ /**
+ * Creates new instance of this dialog fragment
+ *
+ * @param title title of dialog
+ * @param messenger to communicate back after setting the passphrase
+ * @return
+ */
+ public static AddKeyserverDialogFragment newInstance(Messenger messenger, int title) {
+ AddKeyserverDialogFragment frag = new AddKeyserverDialogFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_TITLE, title);
+ args.putParcelable(ARG_MESSENGER, messenger);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ /**
+ * Creates dialog
+ */
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+
+ int title = getArguments().getInt(ARG_TITLE);
+ mMessenger = getArguments().getParcelable(ARG_MESSENGER);
+
+ CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
+
+ alert.setTitle(title);
+
+ LayoutInflater inflater = activity.getLayoutInflater();
+ View view = inflater.inflate(R.layout.add_keyserver_dialog, null);
+ alert.setView(view);
+
+ mKeyserverEditText = (EditText) view.findViewById(R.id.keyserver_url_edit_text);
+ mVerifyKeyserverCheckBox = (CheckBox) view.findViewById(R.id.verify_keyserver_checkbox);
+
+ // we don't want dialog to be dismissed on click, thereby requiring the hack seen below
+ // and in onStart
+ alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ // we need to have an empty listener to prevent errors on some devices as mentioned
+ // at http://stackoverflow.com/q/13746412/3000919
+ // actual listener set in onStart
+ }
+ });
+
+ alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dismiss();
+ }
+ });
+
+ // Hack to open keyboard.
+ // This is the only method that I found to work across all Android versions
+ // http://turbomanage.wordpress.com/2012/05/02/show-soft-keyboard-automatically-when-edittext-receives-focus/
+ // Notes: * onCreateView can't be used because we want to add buttons to the dialog
+ // * opening in onActivityCreated does not work on Android 4.4
+ mKeyserverEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mKeyserverEditText.post(new Runnable() {
+ @Override
+ public void run() {
+ InputMethodManager imm = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mKeyserverEditText, InputMethodManager.SHOW_IMPLICIT);
+ }
+ });
+ }
+ });
+ mKeyserverEditText.requestFocus();
+
+ mKeyserverEditText.setImeActionLabel(getString(android.R.string.ok),
+ EditorInfo.IME_ACTION_DONE);
+ mKeyserverEditText.setOnEditorActionListener(this);
+
+ return alert.show();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ AlertDialog addKeyserverDialog = (AlertDialog) getDialog();
+ if (addKeyserverDialog != null) {
+ Button positiveButton = addKeyserverDialog.getButton(Dialog.BUTTON_POSITIVE);
+ positiveButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String keyserverUrl = mKeyserverEditText.getText().toString();
+ if (mVerifyKeyserverCheckBox.isChecked()) {
+ verifyConnection(keyserverUrl);
+ } else {
+ dismiss();
+ // return unverified keyserver back to activity
+ addKeyserver(keyserverUrl, false);
+ }
+ }
+ });
+ }
+ }
+
+ public void addKeyserver(String keyserver, boolean verified) {
+ dismiss();
+ Bundle data = new Bundle();
+ data.putString(MESSAGE_KEYSERVER, keyserver);
+ data.putBoolean(MESSAGE_VERIFIED, verified);
+
+ sendMessageToHandler(MESSAGE_OKAY, data);
+ }
+
+ public void verificationFailed(FailureReason reason) {
+ Bundle data = new Bundle();
+ data.putSerializable(MESSAGE_FAILURE_REASON, reason);
+
+ sendMessageToHandler(MESSAGE_VERIFICATION_FAILED, data);
+ }
+
+ public void verifyConnection(String keyserver) {
+
+ new AsyncTask<String, Void, FailureReason>() {
+ ProgressDialog mProgressDialog;
+ String mKeyserver;
+
+ @Override
+ protected void onPreExecute() {
+ mProgressDialog = new ProgressDialog(getActivity());
+ mProgressDialog.setMessage(getString(R.string.progress_verifying_keyserver_url));
+ mProgressDialog.setCancelable(false);
+ mProgressDialog.show();
+ }
+
+ @Override
+ protected FailureReason doInBackground(String... keyservers) {
+ mKeyserver = keyservers[0];
+ FailureReason reason = null;
+ try {
+ // replace hkps/hkp scheme and reconstruct Uri
+ Uri keyserverUri = Uri.parse(mKeyserver);
+ String scheme = keyserverUri.getScheme();
+ String schemeSpecificPart = keyserverUri.getSchemeSpecificPart();
+ String fragment = keyserverUri.getFragment();
+ if (scheme == null) throw new MalformedURLException();
+ if (scheme.equalsIgnoreCase("hkps")) scheme = "https";
+ else if (scheme.equalsIgnoreCase("hkp")) scheme = "http";
+ URI newKeyserver = new URI(scheme, schemeSpecificPart, fragment);
+
+ Log.d("Converted URL", newKeyserver.toString());
+ TlsHelper.openConnection(newKeyserver.toURL()).getInputStream();
+ } catch (TlsHelper.TlsHelperException e) {
+ reason = FailureReason.CONNECTION_FAILED;
+ } catch (MalformedURLException e) {
+ Log.w(Constants.TAG, "Invalid keyserver URL entered by user.");
+ reason = FailureReason.INVALID_URL;
+ } catch (URISyntaxException e) {
+ Log.w(Constants.TAG, "Invalid keyserver URL entered by user.");
+ reason = FailureReason.INVALID_URL;
+ } catch (IOException e) {
+ Log.w(Constants.TAG, "Could not connect to entered keyserver url");
+ reason = FailureReason.CONNECTION_FAILED;
+ }
+ return reason;
+ }
+
+ @Override
+ protected void onPostExecute(FailureReason failureReason) {
+ mProgressDialog.dismiss();
+ if (failureReason == null) {
+ addKeyserver(mKeyserver, true);
+ } else {
+ verificationFailed(failureReason);
+ }
+ }
+ }.execute(keyserver);
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+
+ // hide keyboard on dismiss
+ hideKeyboard();
+ }
+
+ private void hideKeyboard() {
+ if (getActivity() == null) {
+ return;
+ }
+ InputMethodManager inputManager = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ //check if no view has focus:
+ View v = getActivity().getCurrentFocus();
+ if (v == null)
+ return;
+
+ inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ }
+
+ /**
+ * Associate the "done" button on the soft keyboard with the okay button in the view
+ */
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (EditorInfo.IME_ACTION_DONE == actionId) {
+ AlertDialog dialog = ((AlertDialog) getDialog());
+ Button bt = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
+
+ bt.performClick();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Send message back to handler which is initialized in a activity
+ *
+ * @param what Message integer you want to send
+ */
+ private void sendMessageToHandler(Integer what, Bundle data) {
+ Message msg = Message.obtain();
+ msg.what = what;
+ if (data != null) {
+ msg.setData(data);
+ }
+
+ try {
+ mMessenger.send(msg);
+ } catch (RemoteException e) {
+ Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
+ } catch (NullPointerException e) {
+ Log.w(Constants.TAG, "Messenger is null!", e);
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java
index e21c5d510..e55f6b1ad 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java
@@ -17,9 +17,8 @@
package org.sufficientlysecure.keychain.ui.widget;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.os.Build;
+import android.support.v7.widget.AppCompatAutoCompleteTextView;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
@@ -27,14 +26,13 @@ import android.util.AttributeSet;
import android.util.Patterns;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.ContactHelper;
import java.util.regex.Matcher;
-public class EmailEditText extends AutoCompleteTextView {
+public class EmailEditText extends AppCompatAutoCompleteTextView {
public EmailEditText(Context context) {
super(context);
@@ -51,12 +49,6 @@ public class EmailEditText extends AutoCompleteTextView {
init();
}
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
private void init() {
setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
reenableKeyboardSuggestions();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
index 5a6c61f7d..8cf15a75a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -25,7 +25,7 @@ import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
-import android.support.v7.internal.widget.TintSpinner;
+import android.support.v7.widget.AppCompatSpinner;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.View;
@@ -47,10 +47,10 @@ import java.util.Date;
import java.util.TimeZone;
/**
- * Use TintSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon.
+ * Use AppCompatSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon.
* Related: http://stackoverflow.com/a/27713090
*/
-public abstract class KeySpinner extends TintSpinner implements LoaderManager.LoaderCallbacks<Cursor> {
+public abstract class KeySpinner extends AppCompatSpinner implements LoaderManager.LoaderCallbacks<Cursor> {
public interface OnKeyChangedListener {
public void onKeyChanged(long masterKeyId);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java
index 153bf2ff2..1a034537c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java
@@ -17,17 +17,15 @@
package org.sufficientlysecure.keychain.ui.widget;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.os.Build;
+import android.support.v7.widget.AppCompatAutoCompleteTextView;
import android.util.AttributeSet;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
import org.sufficientlysecure.keychain.util.ContactHelper;
-public class NameEditText extends AutoCompleteTextView {
+public class NameEditText extends AppCompatAutoCompleteTextView {
public NameEditText(Context context) {
super(context);
init();
@@ -43,12 +41,6 @@ public class NameEditText extends AutoCompleteTextView {
init();
}
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public NameEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
private void init() {
reenableKeyboardSuggestions();
initAdapter();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java
index 377f701d1..9364c5ee9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PassphraseEditText.java
@@ -19,15 +19,13 @@ package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
import android.graphics.Canvas;
+import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.TypedValue;
-import android.widget.EditText;
-import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthBarView;
-
-public class PassphraseEditText extends EditText {
+public class PassphraseEditText extends AppCompatEditText {
PasswordStrengthBarView mPasswordStrengthBarView;
int mPasswordBarWidth;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthBarView.java
index 9e06c4cce..e5886345f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthBarView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthBarView.java
@@ -22,13 +22,10 @@
* SOFTWARE.
*/
-package org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator;
+package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
/**
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java
index bc5018497..1487c3053 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/passwordstrengthindicator/PasswordStrengthView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-package org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator;
+package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
@@ -56,7 +56,6 @@ import org.sufficientlysecure.keychain.R;
*/
public class PasswordStrengthView extends View {
-
protected int mMinWidth;
protected int mMinHeight;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
index 8a7638054..303687315 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
@@ -193,6 +193,11 @@ public class Preferences {
public final boolean searchKeybase;
public final String keyserver;
+ /**
+ * @param searchKeyserver should passed keyserver be searched
+ * @param searchKeybase should keybase.io be searched
+ * @param keyserver the keyserver url authority to search on
+ */
public CloudSearchPrefs(boolean searchKeyserver, boolean searchKeybase, String keyserver) {
this.searchKeyserver = searchKeyserver;
this.searchKeybase = searchKeybase;
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.png
new file mode 100644
index 000000000..dc8c85cce
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png
new file mode 100644
index 000000000..2839b1352
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.png
new file mode 100644
index 000000000..4ad9e552d
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png
new file mode 100644
index 000000000..f0ff945b8
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.png
new file mode 100644
index 000000000..c6f0e6b85
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png
new file mode 100644
index 000000000..4b3675766
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.png
new file mode 100644
index 000000000..081fbec5b
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png
new file mode 100644
index 000000000..09d4df6af
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.png
new file mode 100644
index 000000000..04c07fb56
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png
new file mode 100644
index 000000000..0fe15fc05
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml
new file mode 100644
index 000000000..78e9247ea
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="16dp"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="16dp">
+
+ <EditText
+ android:id="@+id/keyserver_url_edit_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="8dp"
+ android:ems="10"
+ android:hint="@string/label_enter_keyserver_url"
+ android:imeOptions="actionDone" />
+
+ <CheckBox
+ android:id="@+id/verify_keyserver_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/label_verify_keyserver"
+ android:checked="true"/>
+
+</LinearLayout> \ 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
index a6099e25e..41d7c5c95 100644
--- a/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml
+++ b/OpenKeychain/src/main/res/layout/decrypt_text_activity.xml
@@ -5,7 +5,7 @@
<include
android:id="@+id/toolbar_include"
- layout="@layout/toolbar_standalone_white" />
+ layout="@layout/toolbar_result_decrypt" />
<!--
fitsSystemWindows and layout_marginTop from
diff --git a/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml b/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml
index efdbf03c0..2fedefd03 100644
--- a/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml
@@ -5,7 +5,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <include layout="@layout/decrypt_result_include" />
+ <!--<include layout="@layout/decrypt_result_include" />-->
<LinearLayout
android:visibility="gone"
diff --git a/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml
index b75ec5022..8fd2c79fc 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
@@ -12,4 +12,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
-</LinearLayout> \ No newline at end of file
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml
index 3c21291cd..7645918f4 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml
@@ -1,25 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true">
+ android:layout_height="match_parent">
- <LinearLayout
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="4dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:orientation="vertical">
+ android:layout_height="match_parent"
+ android:fillViewport="true">
<EditText
android:id="@+id/encrypt_text_text"
android:layout_width="match_parent"
- android:layout_height="0dip"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
android:gravity="top"
android:inputType="text|textCapSentences|textMultiLine|textLongMessage"
- android:hint="@string/encrypt_content_edit_text_hint"
- android:layout_weight="1" />
+ android:hint="@string/encrypt_content_edit_text_hint" />
- </LinearLayout>
-</ScrollView>
+ </ScrollView>
+
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/main_activity.xml b/OpenKeychain/src/main/res/layout/main_activity.xml
new file mode 100644
index 000000000..4a07053ea
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/main_activity.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/activity_main_toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:elevation="4dp"
+ android:background="?attr/colorPrimary"/>
+
+ <FrameLayout
+ android:id="@+id/main_fragment_container"
+ android:layout_gravity="center"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/main_drawer_header.xml b/OpenKeychain/src/main/res/layout/main_drawer_header.xml
new file mode 100644
index 000000000..bac52efb3
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/main_drawer_header.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/drawer_header"
+ android:adjustViewBounds="true"
+ android:scaleType="fitCenter">
+</ImageView> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml b/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
index 5f323716c..ffc5266b5 100644
--- a/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
@@ -33,7 +33,7 @@
android:ems="10"
android:layout_gravity="center_horizontal" />
- <org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthBarView
+ <org.sufficientlysecure.keychain.ui.widget.PasswordStrengthBarView
android:id="@+id/passphrase_repeat_passphrase_strength"
android:layout_width="48dp"
android:layout_height="8dp"
diff --git a/OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml b/OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml
new file mode 100644
index 000000000..fe421449a
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/toolbar_include"
+ android:elevation="4dp"
+ android:background="@color/white"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <include
+ android:id="@+id/toolbar_inner_layout"
+ layout="@layout/toolbar_inner_layout_white" />
+
+ <LinearLayout
+ android:layout_below="@id/toolbar"
+ android:id="@+id/result_main_layout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:showIn="@layout/decrypt_text_fragment">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:animateLayoutChanges="true">
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/result_encryption_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/status_lock_open_24dp"
+ android:layout_gravity="center_vertical" />
+
+ <TextView
+ android:id="@+id/result_encryption_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ tools:text="Encryption status text" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/result_signature_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/status_signature_unverified_cutout_24dp"
+ android:layout_gravity="center_vertical" />
+
+ <TextView
+ android:id="@+id/result_signature_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ tools:text="Signature status text" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/result_signature_layout"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp"
+ android:background="?android:selectableItemBackground"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:paddingRight="4dp"
+ android:paddingLeft="4dp"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/result_signature_name"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:text="Alice" />
+
+ <TextView
+ android:id="@+id/result_signature_email"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ tools:text="alice@example.com" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dip"
+ android:layout_height="match_parent"
+ android:gravity="right"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="8dp"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/result_signature_action"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="Show"
+ android:drawableRight="@drawable/ic_vpn_key_grey_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/menu/decrypt_menu.xml b/OpenKeychain/src/main/res/menu/decrypt_menu.xml
index c0d7a519f..0b81ea1db 100644
--- a/OpenKeychain/src/main/res/menu/decrypt_menu.xml
+++ b/OpenKeychain/src/main/res/menu/decrypt_menu.xml
@@ -5,13 +5,13 @@
<item
android:id="@+id/decrypt_copy"
android:title="@string/btn_copy_decrypted_text"
- android:icon="@drawable/ic_action_encrypt_copy_24dp"
+ android:icon="@drawable/ic_content_copy_black_24dp"
app:showAsAction="ifRoom" />
<item
android:id="@+id/decrypt_share"
android:title="@string/btn_share_decrypted_text"
- android:icon="@drawable/ic_action_encrypt_share_24dp"
+ android:icon="@drawable/ic_share_black_24dp"
app:showAsAction="ifRoom" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/OpenKeychain/src/main/res/raw/help_about.md b/OpenKeychain/src/main/res/raw/help_about.md
index 4b51c1695..65a04e56e 100644
--- a/OpenKeychain/src/main/res/raw/help_about.md
+++ b/OpenKeychain/src/main/res/raw/help_about.md
@@ -6,8 +6,12 @@
License: GPLv3+
-## Developers
+## Main Developers
* Dominik Schürmann (Maintainer)
+ * Vincent Breitmoser
+
+## Contributors
+ * Adithya Abraham Philip
* Art O Cathain
* Ash Hughes
* Brian C. Barnes
@@ -15,18 +19,33 @@ License: GPLv3+
* Daniel Albert
* Daniel Hammann
* Daniel Haß
+ * Daniel Nelz
+ * Daniel Ramos
* Greg Witczak
+ * 'iseki'
+ * Ishan Khanna
+ * 'jellysheep'
+ * 'Jesperbk'
+ * 'jkolo'
+ * Joey Castillo
+ * Kai Jiang
+ * Kartik Arora
+ * 'Kent'
+ * 'ligi'
+ * Lukas Zorich
+ * Manoj Khanna
* 'mar-v-in'
* Markus Doits
* Miroojin Bakshi
+ * Morgan Gangwere
* Nikhil Peter Raj
* Paul Sarbinowski
* 'Senecaso'
* Signe Rüsch
* Sreeram Boyapati
- * Thialfihar (APG 1.x)
+ * 'steelman'
+ * 'Thialfihar' (APG developer)
* Tim Bray
- * Vincent Breitmoser
## Libraries
* [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
@@ -39,8 +58,8 @@ License: GPLv3+
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
* [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design)</a> (Apache License v2)
- * [MaterialNavigationDrawer](https://github.com/neokree/MaterialNavigationDrawer) (Apache License v2)
+ * [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
* [FloatingActionButton](https://github.com/futuresimple/android-floating-action-button) (Apache License v2)
- * [HtmlTextView](https://github.com/dschuermann/html-textview) (Apache License v2)
+ * [HtmlTextView](https://github.com/sufficientlysecure/html-textview) (Apache License v2)
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw/help_changelog.md b/OpenKeychain/src/main/res/raw/help_changelog.md
index 104454f39..98639de71 100644
--- a/OpenKeychain/src/main/res/raw/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw/help_changelog.md
@@ -2,8 +2,9 @@
## 3.2beta2
+ * First version with full YubiKey support available from the user interface: Edit keys, bind YubiKey to keys,...
* Material design
- * Integration of QR Scanner (New permissions required)
+ * Integration of QR Code Scanning (New permissions required)
* Improved key creation wizard
* Fix missing contacts after sync
* Requires Android 4
@@ -13,6 +14,7 @@
* Fix: Some valid keys were shown revoked or expired
* Don't accept signatures by expired or revoked subkeys
* Keybase.io support in advanced view
+ * Method to update all keys at once
## 3.1.2
@@ -35,7 +37,7 @@
* Redesigned decrypt screen
* New icon usage and colors
* Fix import of secret keys from Symantec Encryption Desktop
- * Subkey IDs on YubiKeys are now checked correctly
+ * Experimental YubiKey support: Subkey IDs are now checked correctly
## 3.0.1
@@ -46,7 +48,6 @@
## 3.0
- * Full support for YubiKey signature generation and decryption!
* Propose installable compatible apps in apps list
* New design for decryption screens
* Many fixes for key import, also fixes stripped keys
@@ -55,12 +56,13 @@
* Fixing user id revocation certificates
* New cloud search (searches over traditional keyservers and keybase.io)
* Support for stripping keys inside OpenKeychain
+ * Experimental YubiKey support: Support for signature generation and decryption
## 2.9.2
* Fix keys broken in 2.9.1
- * YubiKey decryption now working via API
+ * Experimental YubiKey support: Decryption now working via API
## 2.9.1
@@ -69,7 +71,7 @@
* Fix key flags handling (now supporting Mailvelope 0.7 keys)
* Improved passphrase handling
* Key sharing via SafeSlinger
- * YubiKey: preference to allow other PINs, currently only signing via the OpenPGP API works, not inside of OpenKeychain
+ * Experimental YubiKey support: Preference to allow other PINs, currently only signing via the OpenPGP API works, not inside of OpenKeychain
* Fix usage of stripped keys
* SHA256 as default for compatibility
* Intent API has changed, see https://github.com/open-keychain/open-keychain/wiki/Intent-API
@@ -80,7 +82,7 @@
* Fixing crashes introduced in v2.8
* Experimental ECC support
- * Experimental YubiKey support (signing-only with imported keys)
+ * Experimental YubiKey support: Only signing with imported keys
## 2.8
diff --git a/OpenKeychain/src/main/res/values/colors.xml b/OpenKeychain/src/main/res/values/colors.xml
index 8c5358fd0..ead006a63 100644
--- a/OpenKeychain/src/main/res/values/colors.xml
+++ b/OpenKeychain/src/main/res/values/colors.xml
@@ -22,6 +22,7 @@
<color name="secondary_text">#727272</color>
<color name="icons">#FFFFFF</color>
<color name="divider">#B6B6B6</color>
+ <color name="transparent">#00FFFFFF</color>
<color name="header_text">#212121</color>
<!-- item selection, search highlight -->
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 55aec5e6d..666d277c3 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -88,6 +88,7 @@
<string name="btn_encrypt_text">"Encrypt text"</string>
<string name="btn_add_email">"Add additional email address"</string>
<string name="btn_unlock">"Unlock"</string>
+ <string name="btn_add_keyserver">"Add"</string>
<!-- menu -->
<string name="menu_preferences">"Settings"</string>
@@ -154,6 +155,8 @@
<string name="label_enable_compression">"Enable compression"</string>
<string name="label_encrypt_filenames">"Encrypt filenames"</string>
<string name="label_hidden_recipients">"Hide recipients"</string>
+ <string name="label_verify_keyserver">"Verify Keyserver"</string>
+ <string name="label_enter_keyserver_url">"Enter Keyserver URL"</string>
<string name="pref_keyserver">"Search Keyserver"</string>
<string name="pref_keyserver_summary">"Search HKP keyserver"</string>
@@ -356,6 +359,8 @@
<string name="progress_con_saving">"consolidate: saving to cache…"</string>
<string name="progress_con_reimport">"consolidate: reimporting…"</string>
+ <string name="progress_verifying_keyserver_url">"verifying keyserver…"</string>
+
<!-- action strings -->
<string name="hint_cloud_search_hint">"Search via Name, Email…"</string>
@@ -407,6 +412,9 @@
<string name="import_qr_code_button">"Scan QR Code"</string>
<string name="import_qr_code_text">"Place your camera over the QR Code!"</string>
+ <!-- Import from URL -->
+ <string name="import_url_warn_no_search_parameter">"No search parameter found. You may still attempt manually searching the keyserver."</string>
+
<!-- Generic result toast -->
<string name="view_log">"Details"</string>
<string name="with_warnings">", with warnings"</string>
@@ -645,6 +653,13 @@
<string name="view_key_fragment_no_system_contact">"&lt;none&gt;"</string>
+ <!-- Add keyserver -->
+ <string name="add_keyserver_dialog_title">"Add Keyserver"</string>
+ <string name="add_keyserver_verified">"Keyserver verified!"</string>
+ <string name="add_keyserver_without_verification">"Keyserver added without verification."</string>
+ <string name="add_keyserver_invalid_url">"Invalid URL!"</string>
+ <string name="add_keyserver_connection_failed">"Failed to connect to keyserver. Please check the URL and your internet connection."</string>
+
<!-- Navigation Drawer -->
<string name="nav_keys">"Keys"</string>
<string name="nav_encrypt_decrypt">"Encrypt/Decrypt"</string>
@@ -1248,6 +1263,7 @@
<string name="swipe_to_update">"Swipe down to update from keyserver"</string>
<string name="error_no_file_selected">"Select at least one file to encrypt!"</string>
<string name="error_multi_not_supported">"Saving of multiple files not supported. This is a limitation on current Android."</string>
+ <string name="error_empty_text">"Type some text to encrypt!"</string>
<string name="key_colon">"Key:"</string>
<string name="exchange_description">"To start a key exchange, choose the number of participants on the right side, then hit the “Start exchange” button.\n\nYou will be asked two more questions to make sure only the right participants are in the exchange and their fingerprints are correct."</string>
<string name="btn_start_exchange">"Start exchange"</string>
diff --git a/OpenKeychain/src/main/res/values/themes.xml b/OpenKeychain/src/main/res/values/themes.xml
index c87895c01..96d09151d 100644
--- a/OpenKeychain/src/main/res/values/themes.xml
+++ b/OpenKeychain/src/main/res/values/themes.xml
@@ -8,26 +8,17 @@
<item name="colorPrimaryDark">@color/primary_dark</item>
<item name="colorAccent">@color/accent</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="windowNoTitle">true</item>
<!-- remove actionbar, we use toolbar! -->
<item name="windowActionBar">false</item>
<!-- multi selection should overlay Toolbar! http://stackoverflow.com/a/26450875 -->
<item name="windowActionModeOverlay">true</item>
<item name="searchViewStyle">@style/MySearchViewStyle</item>
- <!-- Navigation Drawer library -->
- <item name="drawerType">@integer/DRAWERTYPE_IMAGE</item>
<!-- dark action bar... -->
<item name="theme">@style/ThemeOverlay.AppCompat.Dark</item>
<!-- ...but light popup menu (white background) -->
<item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
- <item name="drawerColor">#fafafa</item>
- <item name="singleAccount">false</item>
- <item name="sectionStyle">@style/MaterialSectionTheme.Light</item>
- <item name="subheaderStyle">@style/MaterialSubheaderTheme.Light</item>
- <item name="multipaneSupport">false</item>
- <item name="rippleBackport">false</item>
- <item name="uniqueToolbarColor">false</item>
</style>
<!-- http://android-developers.blogspot.de/2014/10/appcompat-v21-material-design-for-pre.html -->