aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rwxr-xr-xGraphics/get-material-icons.sh4
-rw-r--r--OpenKeychain/build.gradle69
-rw-r--r--OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/MiscCryptOperationTests.java9
-rw-r--r--OpenKeychain/src/debug/res/drawable-hdpi/ic_stat_notify.pngbin1818 -> 0 bytes
-rw-r--r--OpenKeychain/src/debug/res/drawable-mdpi/ic_stat_notify.pngbin1181 -> 0 bytes
-rw-r--r--OpenKeychain/src/debug/res/drawable-xhdpi/ic_stat_notify.pngbin2516 -> 0 bytes
-rw-r--r--OpenKeychain/src/debug/res/drawable-xxhdpi/ic_stat_notify.pngbin3725 -> 0 bytes
-rw-r--r--OpenKeychain/src/debug/res/drawable-xxxhdpi/ic_stat_notify.pngbin5052 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java28
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java27
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java111
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java88
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java79
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java114
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java106
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java29
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java145
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java123
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java91
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java110
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java38
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java26
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java46
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java16
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java66
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java53
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java76
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java84
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java174
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java26
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java89
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java143
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java58
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyBlankFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java)8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java)26
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java134
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java152
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyWaitFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java)2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java128
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java427
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java99
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java44
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java40
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpMarkdownFragment.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java54
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java27
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java206
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java15
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java83
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java143
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java91
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java82
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java88
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java303
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java194
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java367
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java330
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java30
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java46
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java44
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java245
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java104
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java172
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java93
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java)123
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEmailDialogFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java211
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyDialogFragment.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java29
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/OrbotStartDialogFragment.java126
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PreferenceInstallDialogFragment.java75
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SupportInstallDialogFragment.java76
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Highlighter.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/InstallDialogFragmentHelper.java132
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java39
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ThemeChanger.java73
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java106
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperAdapter.java41
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperDragCallback.java92
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperViewHolder.java39
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/RecyclerItemClickListener.java70
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java28
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java84
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java40
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java88
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java119
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java51
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java252
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/TorServiceUtils.java144
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_add_white_24dp.pngbin0 -> 127 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.pngbin182 -> 96 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.pngbin287 -> 152 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_check_circle_black_48dp.pngbin0 -> 709 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.pngbin309 -> 181 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_close_black_24dp.pngbin301 -> 207 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.pngbin324 -> 221 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_content_copy_black_24dp.pngbin284 -> 195 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_delete_white_24dp.pngbin0 -> 161 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.pngbin234 -> 149 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.pngbin244 -> 151 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_folder_white_24dp.pngbin224 -> 135 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_help_black_24dp.pngbin559 -> 458 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_lock_black_24dp.pngbin397 -> 308 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_lock_white_24dp.pngbin399 -> 309 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_mode_edit_white_24dp.pngbin351 -> 219 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.pngbin282 -> 195 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.pngbin531 -> 387 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_reorder_grey_500_24dp.pngbin0 -> 134 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_repeat_white_24dp.pngbin296 -> 198 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_save_white_24dp.pngbin341 -> 247 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_search_white_24dp.pngbin504 -> 396 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_settings_black_24dp.pngbin561 -> 453 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.pngbin499 -> 398 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_stat_retyped_bad.png (renamed from OpenKeychain/src/main/res/drawable-hdpi/uid_mail_bad.png)bin942 -> 942 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_stat_retyped_ok.png (renamed from OpenKeychain/src/main/res/drawable-hdpi/uid_mail_ok.png)bin1252 -> 1252 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.pngbin381 -> 282 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_add_white_24dp.pngbin0 -> 88 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.pngbin173 -> 84 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.pngbin240 -> 118 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_check_circle_black_48dp.pngbin0 -> 493 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.pngbin243 -> 137 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_close_black_24dp.pngbin257 -> 164 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_24dp.pngbin279 -> 175 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_content_copy_black_24dp.pngbin214 -> 130 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_delete_white_24dp.pngbin0 -> 115 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.pngbin206 -> 126 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.pngbin206 -> 125 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_folder_white_24dp.pngbin206 -> 122 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_help_black_24dp.pngbin390 -> 298 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_lock_black_24dp.pngbin291 -> 205 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_lock_white_24dp.pngbin296 -> 208 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_mode_edit_white_24dp.pngbin272 -> 165 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.pngbin257 -> 157 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.pngbin346 -> 254 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_reorder_grey_500_24dp.pngbin0 -> 101 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_repeat_white_24dp.pngbin236 -> 133 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_save_white_24dp.pngbin257 -> 168 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_search_white_24dp.pngbin346 -> 247 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_settings_black_24dp.pngbin416 -> 322 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.pngbin355 -> 262 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_stat_retyped_bad.png (renamed from OpenKeychain/src/main/res/drawable-mdpi/uid_mail_bad.png)bin647 -> 647 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_stat_retyped_ok.png (renamed from OpenKeychain/src/main/res/drawable-mdpi/uid_mail_ok.png)bin862 -> 862 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.pngbin293 -> 196 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_add_white_24dp.pngbin0 -> 97 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.pngbin193 -> 105 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.pngbin336 -> 151 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_check_circle_black_48dp.pngbin0 -> 922 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.pngbin363 -> 199 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_close_black_24dp.pngbin360 -> 235 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_24dp.pngbin402 -> 257 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_content_copy_black_24dp.pngbin304 -> 180 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_delete_white_24dp.pngbin0 -> 151 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.pngbin259 -> 171 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.pngbin272 -> 168 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_folder_white_24dp.pngbin273 -> 181 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_help_black_24dp.pngbin700 -> 579 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_black_24dp.pngbin498 -> 365 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_white_24dp.pngbin465 -> 372 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_mode_edit_white_24dp.pngbin378 -> 239 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.pngbin318 -> 220 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.pngbin637 -> 509 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_reorder_grey_500_24dp.pngbin0 -> 138 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_repeat_white_24dp.pngbin314 -> 185 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_save_white_24dp.pngbin359 -> 273 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_search_white_24dp.pngbin591 -> 465 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_black_24dp.pngbin691 -> 557 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.pngbin614 -> 483 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_retyped_bad.png (renamed from OpenKeychain/src/main/res/drawable-xhdpi/uid_mail_bad.png)bin1299 -> 1299 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_retyped_ok.png (renamed from OpenKeychain/src/main/res/drawable-xhdpi/uid_mail_ok.png)bin1606 -> 1606 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.pngbin446 -> 342 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_add_white_24dp.pngbin0 -> 97 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.pngbin213 -> 115 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.pngbin410 -> 188 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_circle_black_48dp.pngbin0 -> 1346 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.pngbin460 -> 276 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_black_24dp.pngbin425 -> 309 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_24dp.pngbin492 -> 347 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_content_copy_black_24dp.pngbin397 -> 258 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.pngbin0 -> 194 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.pngbin304 -> 213 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.pngbin316 -> 215 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_folder_white_24dp.pngbin342 -> 245 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_help_black_24dp.pngbin986 -> 834 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_black_24dp.pngbin636 -> 527 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.pngbin760 -> 540 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_mode_edit_white_24dp.pngbin490 -> 302 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.pngbin399 -> 283 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.pngbin875 -> 734 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_reorder_grey_500_24dp.pngbin0 -> 186 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_repeat_white_24dp.pngbin397 -> 234 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_save_white_24dp.pngbin489 -> 391 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_search_white_24dp.pngbin871 -> 728 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.pngbin969 -> 827 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.pngbin804 -> 675 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_retyped_bad.png (renamed from OpenKeychain/src/main/res/drawable-xxhdpi/uid_mail_bad.png)bin2338 -> 2338 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_retyped_ok.png (renamed from OpenKeychain/src/main/res/drawable-xxhdpi/uid_mail_ok.png)bin2364 -> 2364 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.pngbin622 -> 476 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.pngbin0 -> 102 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.pngbin236 -> 114 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.pngbin530 -> 231 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_circle_black_48dp.pngbin0 -> 1812 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.pngbin587 -> 308 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_black_24dp.pngbin565 -> 377 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.pngbin662 -> 436 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_content_copy_black_24dp.pngbin480 -> 319 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.pngbin0 -> 243 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.pngbin360 -> 261 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.pngbin379 -> 256 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_folder_white_24dp.pngbin504 -> 325 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_help_black_24dp.pngbin1323 -> 1122 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_black_24dp.pngbin830 -> 685 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.pngbin971 -> 702 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_24dp.pngbin632 -> 355 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.pngbin477 -> 343 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.pngbin1148 -> 967 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_repeat_white_24dp.pngbin478 -> 257 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_save_white_24dp.pngbin747 -> 504 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.pngbin1090 -> 915 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_black_24dp.pngbin1257 -> 1073 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.pngbin1052 -> 888 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.pngbin789 -> 636 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable/cardview_header.xml4
-rw-r--r--OpenKeychain/src/main/res/drawable/fab_label_background.xml4
-rw-r--r--OpenKeychain/src/main/res/drawable/section_header.xml4
-rw-r--r--OpenKeychain/src/main/res/drawable/selector_transparent_button.xml7
-rw-r--r--OpenKeychain/src/main/res/drawable/yubikey_phone.pngbin352625 -> 347902 bytes
-rw-r--r--OpenKeychain/src/main/res/layout/add_user_id_dialog.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/api_app_settings_activity.xml6
-rw-r--r--OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/backup_fragment.xml71
-rw-r--r--OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_email_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_final_fragment.xml12
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_name_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_start_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml109
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml110
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/decrypt_list_entry.xml36
-rw-r--r--OpenKeychain/src/main/res/layout/del_rev_dialog.xml24
-rw-r--r--OpenKeychain/src/main/res/layout/drawer_custom_header.xml16
-rw-r--r--OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml207
-rw-r--r--OpenKeychain/src/main/res/layout/file_list_entry.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/foldable_linearlayout.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/help_about_fragment.xml23
-rw-r--r--OpenKeychain/src/main/res/layout/import_keys_activity.xml24
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_content.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_fragment.xml18
-rw-r--r--OpenKeychain/src/main/res/layout/key_server_preference.xml117
-rw-r--r--OpenKeychain/src/main/res/layout/log_display_item.xml6
-rw-r--r--OpenKeychain/src/main/res/layout/nfc_activity.xml35
-rw-r--r--OpenKeychain/src/main/res/layout/nfc_operation_activity.xml179
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml8
-rw-r--r--OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/settings_keyserver_fragment.xml7
-rw-r--r--OpenKeychain/src/main/res/layout/settings_keyserver_item.xml46
-rw-r--r--OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/toolbar_standalone_white.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/toolbar_tabs.xml6
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_activity.xml8
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_adv_certs_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml17
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_adv_user_id_item.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_yubikey.xml2
-rw-r--r--OpenKeychain/src/main/res/menu/key_list.xml5
-rw-r--r--OpenKeychain/src/main/res/menu/key_list_multi.xml19
-rw-r--r--OpenKeychain/src/main/res/menu/keyserver_pref_menu.xml10
-rw-r--r--OpenKeychain/src/main/res/raw-ar/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-bg/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-de/help_changelog.md67
-rw-r--r--OpenKeychain/src/main/res/raw-es/help_about.md2
-rw-r--r--OpenKeychain/src/main/res/raw-es/help_changelog.md11
-rw-r--r--OpenKeychain/src/main/res/raw-et/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-eu/help_about.md2
-rw-r--r--OpenKeychain/src/main/res/raw-eu/help_changelog.md21
-rw-r--r--OpenKeychain/src/main/res/raw-fi/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-fr/help_about.md2
-rw-r--r--OpenKeychain/src/main/res/raw-fr/help_changelog.md23
-rw-r--r--OpenKeychain/src/main/res/raw-is/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-it/help_about.md2
-rw-r--r--OpenKeychain/src/main/res/raw-it/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-ja/help_changelog.md11
-rw-r--r--OpenKeychain/src/main/res/raw-kn/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-nl/help_about.md2
-rw-r--r--OpenKeychain/src/main/res/raw-nl/help_changelog.md11
-rw-r--r--OpenKeychain/src/main/res/raw-pl/help_about.md10
-rw-r--r--OpenKeychain/src/main/res/raw-pl/help_certification.md6
-rw-r--r--OpenKeychain/src/main/res/raw-pl/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-pt/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-ro/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-ru/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-sl/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-sr/help_about.md2
-rw-r--r--OpenKeychain/src/main/res/raw-sr/help_changelog.md13
-rw-r--r--OpenKeychain/src/main/res/raw-sv/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-tr/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-uk/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-vi/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw-zh/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/raw/help_changelog.md5
-rw-r--r--OpenKeychain/src/main/res/values-ar/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-bg/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-cs/strings.xml15
-rw-r--r--OpenKeychain/src/main/res/values-de/strings.xml50
-rw-r--r--OpenKeychain/src/main/res/values-es/strings.xml95
-rw-r--r--OpenKeychain/src/main/res/values-et/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-eu/strings.xml162
-rw-r--r--OpenKeychain/src/main/res/values-fi/strings.xml10
-rw-r--r--OpenKeychain/src/main/res/values-fr/strings.xml114
-rw-r--r--OpenKeychain/src/main/res/values-is/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-it/strings.xml60
-rw-r--r--OpenKeychain/src/main/res/values-ja/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-kn/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-nl/strings.xml92
-rw-r--r--OpenKeychain/src/main/res/values-pl/strings.xml13
-rw-r--r--OpenKeychain/src/main/res/values-pt/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-ro/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-ru/strings.xml2
-rw-r--r--OpenKeychain/src/main/res/values-sl/strings.xml15
-rw-r--r--OpenKeychain/src/main/res/values-sr/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-sv/strings.xml17
-rw-r--r--OpenKeychain/src/main/res/values-tr/strings.xml13
-rw-r--r--OpenKeychain/src/main/res/values-uk/strings.xml12
-rw-r--r--OpenKeychain/src/main/res/values-v21/themes.xml17
-rw-r--r--OpenKeychain/src/main/res/values-vi/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-zh-rTW/strings.xml16
-rw-r--r--OpenKeychain/src/main/res/values-zh/strings.xml9
-rw-r--r--OpenKeychain/src/main/res/values/arrays.xml20
-rw-r--r--OpenKeychain/src/main/res/values/attrs.xml21
-rw-r--r--OpenKeychain/src/main/res/values/colors.xml59
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml173
-rw-r--r--OpenKeychain/src/main/res/values/styles.xml16
-rw-r--r--OpenKeychain/src/main/res/values/themes.xml76
-rw-r--r--OpenKeychain/src/main/res/xml/account_desc.xml1
-rw-r--r--OpenKeychain/src/main/res/xml/account_preferences.xml10
-rw-r--r--OpenKeychain/src/main/res/xml/gui_preferences.xml10
-rw-r--r--OpenKeychain/src/main/res/xml/preference_headers.xml6
-rw-r--r--OpenKeychain/src/main/res/xml/proxy_prefs.xml34
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java13
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java21
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java144
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java40
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java7
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java12
m---------extern/KeybaseLib0
m---------extern/safeslinger-exchange0
m---------extern/snackbar0
-rw-r--r--gradle/wrapper/gradle-wrapper.properties6
-rw-r--r--settings.gradle3
-rwxr-xr-xtools/checkstyle2
433 files changed, 8799 insertions, 2871 deletions
diff --git a/.gitmodules b/.gitmodules
index 9d4e0f9dd..db9342d20 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -22,3 +22,6 @@
path = extern/safeslinger-exchange
url = https://github.com/open-keychain/exchange-android
ignore = dirty
+[submodule "extern/snackbar"]
+ path = extern/snackbar
+ url = https://github.com/open-keychain/snackbar
diff --git a/Graphics/get-material-icons.sh b/Graphics/get-material-icons.sh
index 11e0cda18..758ddc8aa 100755
--- a/Graphics/get-material-icons.sh
+++ b/Graphics/get-material-icons.sh
@@ -59,3 +59,7 @@ python copy OpenKeychain file white folder 24
# multi select
python copy OpenKeychain action white lock 24
+python copy OpenKeychain action white delete 24
+
+# yubikey dialog
+python copy OpenKeychain action black check_circle 48
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle
index 17d0821a1..c74c63688 100644
--- a/OpenKeychain/build.gradle
+++ b/OpenKeychain/build.gradle
@@ -11,15 +11,15 @@ dependencies {
compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.0'
- compile 'com.android.support:recyclerview-v7:22.1.0'
- compile 'com.android.support:cardview-v7:22.1.0'
-
+ compile 'com.android.support:recyclerview-v7:22.2.0'
+ compile 'com.android.support:cardview-v7:22.2.0'
+
// Unit tests in the local JVM with Robolectric
// https://developer.android.com/training/testing/unit-testing/local-unit-tests.html
- // https://github.com/nenick/AndroidStudioAndRobolectric
+ // http://robolectric.org/getting-started/
// http://www.vogella.com/tutorials/Robolectric/article.html
testCompile 'junit:junit:4.12'
- testCompile 'org.robolectric:robolectric:3.0-rc3'
+ testCompile 'org.robolectric:robolectric:3.0'
// UI testing with Espresso
androidTestCompile 'com.android.support.test:runner:0.3'
@@ -48,13 +48,13 @@ dependencies {
compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.0'
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.8.2@aar'
- compile 'com.mikepenz.iconics:library:0.9.1@aar'
+ compile 'org.sufficientlysecure:html-textview:1.2'
+ compile 'com.mikepenz:materialdrawer:3.0.9@aar'
+ compile 'com.mikepenz:iconics:1.0.2'
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'
- compile 'com.nispok:snackbar:2.10.8'
+ compile 'com.squareup.okhttp:okhttp:2.4.0'
// libs as submodules
compile project(':extern:openpgp-api-lib:openpgp-api')
@@ -65,7 +65,8 @@ dependencies {
compile project(':extern:spongycastle:prov')
compile project(':extern:minidns')
compile project(':extern:KeybaseLib:Lib')
- compile project(':extern:safeslinger-exchange')
+ compile project(':extern:safeslinger-exchange:safeslinger-exchange')
+ compile project(':extern:snackbar:lib')
}
// Output of ./gradlew -q calculateChecksums
@@ -75,8 +76,8 @@ dependencyVerification {
'com.android.support:support-v4:7bb6e40a18774aa2595e4d8f9fe0ae14e61670f71a1279272fb0b79b8be71180',
'com.android.support:appcompat-v7:2d5867698410b41f75140c91d6c1e58da74ae0f97baf6e0bdd1f7cc1017ceb2c',
'com.android.support:design:41ff5f700d1bf8c190e1d3ac33582f92ad6e1f3b1080c8b8e2ac4f7b703be76a',
- 'com.android.support:recyclerview-v7:522d323079a29bcd76173bd9bc7535223b4af3e5eefef9d9287df1f9e54d0c10',
- 'com.android.support:cardview-v7:8dc99af71fec000baa4470c3907755264f15f816920861bc015b2babdbb49807',
+ 'com.android.support:recyclerview-v7:3a8da14585fa1c81f06e7cef4d93a7641f0323d8f984ff9a7bd7a6e416b46888',
+ 'com.android.support:cardview-v7:15b934f69f10d85f5adc12231ba1b708618a7daf6e5102af42addf2c67a85e2c',
'com.eftimoff:android-patternview:cec80e7265b8d8278b3c55b5fcdf551e4600ac2c8bf60d8dd76adca538af0b1e',
'com.journeyapps:zxing-android-embedded:702a4f58154dbd9baa80f66b6a15410f7a4d403f3e73b66537a8bfb156b4b718',
'com.journeyapps:zxing-android-integration:562737821b6d34c899b6fd2234ce0a8a31e02ff1fd7c59f6211961ce9767c7c8',
@@ -86,24 +87,25 @@ dependencyVerification {
'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13',
'com.splitwise:tokenautocomplete:20bee71cc59b3828eb000b684d46ddf738efd56b8fee453a509cd16fda42c8cb',
'se.emilsjolander:stickylistheaders:8c05981ec5725be33f7cee5e68c13f3db49cd5c75f1aaeb04024920b1ef96ad4',
- 'org.sufficientlysecure:html-textview:ca24b1522be88378634093815ce9ff1b4920c72e7513a045a7846e14069ef988',
- 'com.mikepenz.materialdrawer:library:970317ed1a3cb96317f7b8d62ff592b3103eb46dfd68d9b244e7143623dc6d7a',
- 'com.mikepenz.iconics:library:4698a36ee4c2af765d0a85779c61474d755b90d66a59020105b6760a8a909e9e',
+ 'org.sufficientlysecure:html-textview:1d3bed31ef837437154de8d2362a0e6b0e59b6c3535d87ee48c2fab12c84f9bb',
+ 'com.mikepenz:materialdrawer:70c3efb3842461db41df6a918ea93969a7da21e63c092be838b153e5a47a17bf',
+ 'com.mikepenz:iconics:c1a02203d8e0d638959463c00af3ab9096e0a7c1ad5928762eb10ef5ce8a63cd',
'com.mikepenz.iconics:octicons-typeface:67ed7d456a9ce5f5307b85f955797bfb3dd674e2f6defb31c6b8bbe2ede290be',
'com.mikepenz.iconics:meteocons-typeface:39a8a9e70cd8287cdb119af57a672a41dd09240dba6697f5a0dbda1ccc33298b',
'com.mikepenz.iconics:community-material-typeface:f1c5afee5f0f10d66beb3ed0df977246a02a9c46de4e05d7c0264bcde53b6b7f',
- 'com.nispok:snackbar:80bebc8e5d8b3d728cd5f2336e2d0c1cc2a6b7dc4b55d36acd6b75a78265590a',
-// 'OpenKeychain.extern:openpgp-api-lib:f05a9215cdad3a6597e4c5ece6fcec92b178d218195a3e88d2c0937c48dd9580',
-// 'OpenKeychain.extern:openkeychain-api-lib:50f6ebb5452d3fdc7be137ccf857a0ff44d55539fcb7b91baef495766ed7f429',
-// 'com.madgag.spongycastle:core:df8fcc028a95ac5ffab3b78c9163f5cfa672e41cd50128ca55d458b6cfbacf4b',
-// 'com.madgag.spongycastle:pg:160b345b10a2c92dc731453eec87037377f66a8e14a0648d404d7b193c4e380d',
-// 'com.madgag.spongycastle:pkix:0b4f3301ea12dd9f25d71770e6ea9f75e0611bf53062543e47be5bc15340a7e4',
-// 'com.madgag.spongycastle:prov:7325942e0b39f5fb35d6380818eed4b826e7dfc7570ad35b696d778049d8c36a',
-// 'OpenKeychain.extern:minidns:77b1786d29469e3b21f9404827cab811edc857cd68bc732cd57f11307c332eae',
-// 'OpenKeychain.extern.KeybaseLib:Lib:c91cda4a75692d8664644cd17d8ac962ce5bc0e266ea26673a639805f1eccbdf',
-// 'OpenKeychain.extern:safeslinger-exchange:d222721bb35408daaab9f46449364b2657112705ee571d7532f81cbeb9c4a73f',
-// 'OpenKeychain.extern.snackbar:lib:52357426e5275412e2063bdf6f0e6b957a3ea74da45e0aef35d22d9afc542e23',
+ 'com.squareup.okhttp:okhttp:bc0da7ac1f5441619faa2082811938acf7df97e4a8e08f0e043ff4937414d5ad',
+// 'OpenKeychain.extern.openpgp-api-lib:openpgp-api:b918e50a7876fad34e4020ee41418039772c5fe8dd36825720ca8ffecb7d0f06',
+// 'OpenKeychain.extern.openkeychain-api-lib:openkeychain-intents:111d7d53b9e920ad3405f8f3eb0ab7bd3aee66d577442452754b83c7c1c1d49a',
+// 'com.madgag.spongycastle:core:97276487be598747ba78c063c90cea7fc3c7ad9bc7aeba03c0b9c98692052b8a',
+// 'com.madgag.spongycastle:pg:da319de706d946f178140959c74aec126f7803f1104dbad89bb1f55a53f6e1a9',
+// 'com.madgag.spongycastle:pkix:979aa4b2aaef94866e0f97b05b1922244eaf8b650f3691a3c44760ff0a41562b',
+// 'com.madgag.spongycastle:prov:902a484219bbf4e395a1c32da65b2453133e195bcc92336dc8c33b7c58edcd60',
+// 'OpenKeychain.extern:minidns:8274d50124d9584e95df0c5da7798269ac9caf0eab560df929c2c658ca624037',
+// 'OpenKeychain.extern.KeybaseLib:Lib:d52e7888cea6de9e077501bb533270b2a86b52cb8af49e5f44ee8c4bb19ea017',
+// 'OpenKeychain.extern.safeslinger-exchange:safeslinger-exchange:76e5da6b4f5f8835b12649e17569f0d0d8d89552815a61383c128545632689d1',
+// 'OpenKeychain.extern.snackbar:lib:6847a73d2680558d35f0b384ac3ed006532c0a2306598b000db94ef18aab62aa',
'com.android.support:support-annotations:beac5cae60bdb597df9af9c916f785c2f71f8c8ae4be9a32d4298dea85496a42',
+ 'com.squareup.okio:okio:b53c1760864e1c39b5275d9023e2a6fbe8f3189e6e67b4c87877b8ec8f92e05a',
]
}
@@ -114,8 +116,8 @@ android {
defaultConfig {
minSdkVersion 15
targetSdkVersion 22
- versionCode 33000
- versionName "3.3"
+ versionCode 34100
+ versionName "3.4.1"
applicationId "org.sufficientlysecure.keychain"
// the androidjunitrunner is broken regarding coverage, see here:
// https://code.google.com/p/android/issues/detail?id=170607
@@ -130,12 +132,12 @@ android {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
-
+
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
-
+
// Reference them in the java files with e.g. BuildConfig.ACCOUNT_TYPE.
buildConfigField "String", "ACCOUNT_TYPE", "\"org.sufficientlysecure.keychain.account\""
@@ -145,13 +147,13 @@ android {
debug {
applicationIdSuffix ".debug"
-
+
// Reference them in the java files with e.g. BuildConfig.ACCOUNT_TYPE.
buildConfigField "String", "ACCOUNT_TYPE", "\"org.sufficientlysecure.keychain.debug.account\""
// Reference them in .xml files.
resValue "string", "account_type", "org.sufficientlysecure.keychain.debug.account"
-
+
// Enable code coverage (Jacoco)
testCoverageEnabled true
}
@@ -203,6 +205,9 @@ android {
packagingOptions {
exclude 'LICENSE.txt'
+ exclude 'META-INF/LICENSE.txt'
+ exclude 'META-INF/NOTICE.txt'
+ exclude '.readme'
}
}
diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/MiscCryptOperationTests.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/MiscCryptOperationTests.java
index 7b4506986..9b26dfb15 100644
--- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/MiscCryptOperationTests.java
+++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/MiscCryptOperationTests.java
@@ -29,8 +29,6 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.action.ViewActions;
import android.support.test.espresso.intent.Intents;
import android.support.test.espresso.intent.rule.IntentsTestRule;
import android.support.test.runner.AndroidJUnit4;
@@ -41,9 +39,9 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.TestHelpers;
-import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.Preferences;
@@ -162,8 +160,9 @@ public class MiscCryptOperationTests {
public void testDecryptNonPgpClipboard() throws Exception {
// decrypt any non-pgp file
- ClipboardReflection.copyToClipboard(mActivity, randomString(0, 50));
-
+ ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, randomString(0, 50));
+ clipboard.setPrimaryClip(clip);
onView(withId(R.id.decrypt_from_clipboard)).perform(click());
{ // decrypt
diff --git a/OpenKeychain/src/debug/res/drawable-hdpi/ic_stat_notify.png b/OpenKeychain/src/debug/res/drawable-hdpi/ic_stat_notify.png
deleted file mode 100644
index b31481995..000000000
--- a/OpenKeychain/src/debug/res/drawable-hdpi/ic_stat_notify.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/debug/res/drawable-mdpi/ic_stat_notify.png b/OpenKeychain/src/debug/res/drawable-mdpi/ic_stat_notify.png
deleted file mode 100644
index 39e799e5a..000000000
--- a/OpenKeychain/src/debug/res/drawable-mdpi/ic_stat_notify.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/debug/res/drawable-xhdpi/ic_stat_notify.png b/OpenKeychain/src/debug/res/drawable-xhdpi/ic_stat_notify.png
deleted file mode 100644
index af1613d40..000000000
--- a/OpenKeychain/src/debug/res/drawable-xhdpi/ic_stat_notify.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/debug/res/drawable-xxhdpi/ic_stat_notify.png b/OpenKeychain/src/debug/res/drawable-xxhdpi/ic_stat_notify.png
deleted file mode 100644
index 9da107396..000000000
--- a/OpenKeychain/src/debug/res/drawable-xxhdpi/ic_stat_notify.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/debug/res/drawable-xxxhdpi/ic_stat_notify.png b/OpenKeychain/src/debug/res/drawable-xxxhdpi/ic_stat_notify.png
deleted file mode 100644
index 5c81db8bf..000000000
--- a/OpenKeychain/src/debug/res/drawable-xxxhdpi/ic_stat_notify.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index b3754d360..35048b936 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -9,15 +9,15 @@
===============
- Last APG 1 version was 10900 (1.0.9 beta 00)
- Keychain starting with versionCode 20000!
-
+
Association of file types to Keychain
=====================================
General remarks about file ending conventions:
- *.gpg,*.pgp for binary files
- *.asc for ascii armored files The actual content can be anything.
-
+
The file ending only shows if it is binary or ascii encoded.
-
+
Remarks about the ugly android:pathPattern:
- We are matching all files with a specific file ending.
This is done in an ugly way because of Android limitations.
@@ -73,7 +73,7 @@
android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
- android:theme="@style/KeychainTheme">
+ android:theme="@style/LightTheme">
<activity
android:name=".ui.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
@@ -682,6 +682,15 @@
<activity
android:name=".ui.PassphraseDialogActivity"
android:theme="@android:style/Theme.NoDisplay" />
+ <activity
+ android:name=".ui.RetryUploadDialogActivity"
+ android:theme="@android:style/Theme.NoDisplay" />
+ <activity
+ android:name=".ui.DeleteKeyDialogActivity"
+ android:theme="@android:style/Theme.NoDisplay" />
+ <activity
+ android:name=".ui.OrbotRequiredDialogActivity"
+ android:theme="@android:style/Theme.NoDisplay" />
<activity android:name=".ui.PassphraseWizardActivity" />
<!--
NOTE: singleTop is set to get NFC foreground dispatch to work.
@@ -692,6 +701,7 @@
-->
<activity
android:name=".ui.NfcOperationActivity"
+ android:theme="@style/KeychainTheme.YubiKeyDialog"
android:allowTaskReparenting="true"
android:launchMode="singleTop"
android:taskAffinity=":Nfc" />
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index d1b37aed2..3d58602ab 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -26,6 +26,8 @@ import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.BuildConfig;
import java.io.File;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
public final class Constants {
@@ -44,6 +46,8 @@ public final class Constants {
public static final String PROVIDER_AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";
public static final String TEMPSTORAGE_AUTHORITY = BuildConfig.APPLICATION_ID + ".tempstorage";
+ public static final String CLIPBOARD_LABEL = "Keychain";
+
// as defined in http://tools.ietf.org/html/rfc3156, section 7
public static final String NFC_MIME = "application/pgp-keys";
@@ -93,11 +97,33 @@ public final class Constants {
public static final String FILE_USE_COMPRESSION = "useFileCompression";
public static final String TEXT_USE_COMPRESSION = "useTextCompression";
public static final String USE_ARMOR = "useArmor";
+ // proxy settings
+ public static final String USE_NORMAL_PROXY = "useNormalProxy";
+ public static final String USE_TOR_PROXY = "useTorProxy";
+ public static final String PROXY_HOST = "proxyHost";
+ public static final String PROXY_PORT = "proxyPort";
+ public static final String PROXY_TYPE = "proxyType";
+ public static final String THEME = "theme";
+
+ public static final class Theme {
+ public static final String LIGHT = "light";
+ public static final String DARK = "dark";
+ public static final String DEFAULT = Constants.Pref.Theme.LIGHT;
+ }
+ }
+
+ /**
+ * information to connect to Orbot's localhost HTTP proxy
+ */
+ public static final class Orbot {
+ public static final String PROXY_HOST = "127.0.0.1";
+ public static final int PROXY_PORT = 8118;
+ public static final Proxy.Type PROXY_TYPE = Proxy.Type.HTTP;
}
public static final class Defaults {
public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, hkps://pgp.mit.edu";
- public static final int PREF_VERSION = 4;
+ public static final int PREF_VERSION = 5;
}
public static final class key {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 627623f47..cd24394d7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PRNGFixes;
import org.sufficientlysecure.keychain.util.Preferences;
@@ -91,12 +92,12 @@ public class KeychainApplication extends Application {
}
brandGlowEffect(getApplicationContext(),
- getApplicationContext().getResources().getColor(R.color.primary));
+ FormattingUtils.getColorFromAttr(getApplicationContext(), R.attr.colorPrimary));
setupAccountAsNeeded(this);
// Update keyserver list as needed
- Preferences.getPreferences(this).updatePreferences();
+ Preferences.getPreferences(this).upgradePreferences();
TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer");
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
index 403e654e4..abf16851d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
@@ -17,28 +17,22 @@
package org.sufficientlysecure.keychain.compatibility;
+
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
+import android.support.annotation.Nullable;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
-import java.lang.reflect.Method;
-
public class ClipboardReflection {
- private static final String clipboardLabel = "Keychain";
-
- public static void copyToClipboard(Context context, String text) {
- ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
-
- ClipData clip = ClipData.newPlainText(clipboardLabel, text);
- clipboard.setPrimaryClip(clip);
-
- }
-
- public static String getClipboardText(Context context) {
+ @Nullable
+ public static String getClipboardText(@Nullable Context context) {
+ if (context == null) {
+ return null;
+ }
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = clipboard.getPrimaryClip();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
index 07799f466..e1d8c0da7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
@@ -21,7 +21,7 @@ import android.os.Build;
import android.os.Handler;
/**
- * Bug on Android >= 4.2
+ * Bug on Android >= 4.2. Fixed in 4.2.2 ?
*
* http://code.google.com/p/android/issues/detail?id=41901
*
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
index c0221fad3..d91dd28bc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
@@ -20,6 +20,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Preferences;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.Vector;
@@ -30,7 +31,8 @@ public class CloudSearch {
private final static long SECONDS = 1000;
- public static ArrayList<ImportKeysListEntry> search(final String query, Preferences.CloudSearchPrefs cloudPrefs)
+ public static ArrayList<ImportKeysListEntry> search(final String query, Preferences.CloudSearchPrefs cloudPrefs,
+ final Proxy proxy)
throws Keyserver.CloudSearchFailureException {
final ArrayList<Keyserver> servers = new ArrayList<>();
@@ -45,31 +47,42 @@ public class CloudSearch {
}
final ImportKeysList results = new ImportKeysList(servers.size());
+ ArrayList<Thread> searchThreads = new ArrayList<>();
for (final Keyserver keyserver : servers) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
- results.addAll(keyserver.search(query));
+ results.addAll(keyserver.search(query, proxy));
} catch (Keyserver.CloudSearchFailureException e) {
problems.add(e);
}
results.finishedAdding(); // notifies if all searchers done
}
};
- new Thread(r).start();
+ Thread searchThread = new Thread(r);
+ searchThreads.add(searchThread);
+ searchThread.start();
}
- // wait for either all the searches to come back, or 10 seconds
- synchronized(results) {
+ // wait for either all the searches to come back, or 10 seconds. If using proxy, wait 30 seconds.
+ synchronized (results) {
try {
- results.wait(10 * SECONDS);
+ if (proxy != null) {
+ results.wait(30 * SECONDS);
+ } else {
+ results.wait(10 * SECONDS);
+ }
+ for (Thread thread : searchThreads) {
+ // kill threads that haven't returned yet
+ thread.interrupt();
+ }
} catch (InterruptedException e) {
}
}
if (results.outstandingSuppliers() > 0) {
- String message = "Launched " + servers.size() + " cloud searchers, but" +
+ String message = "Launched " + servers.size() + " cloud searchers, but " +
results.outstandingSuppliers() + "failed to complete.";
problems.add(new Keyserver.QueryFailedException(message));
}
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 cb8a53e25..2cf6d8b34 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
@@ -18,18 +18,20 @@
package org.sufficientlysecure.keychain.keyimport;
+import com.squareup.okhttp.MediaType;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.RequestBody;
+import com.squareup.okhttp.Response;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.TlsHelper;
-import java.io.BufferedWriter;
import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
+import java.net.Proxy;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
@@ -39,6 +41,7 @@ import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -190,36 +193,52 @@ public class HkpKeyserver extends Keyserver {
return mSecure ? "https://" : "http://";
}
- private HttpURLConnection openConnection(URL url) throws IOException {
- HttpURLConnection conn = null;
+ /**
+ * returns a client with pinned certificate if necessary
+ *
+ * @param url
+ * @param proxy
+ * @return
+ */
+ public static OkHttpClient getClient(URL url, Proxy proxy) throws IOException {
+ OkHttpClient client = new OkHttpClient();
+
try {
- conn = (HttpURLConnection) TlsHelper.openConnection(url);
+ TlsHelper.pinCertificateIfNecessary(client, url);
} catch (TlsHelper.TlsHelperException e) {
Log.w(Constants.TAG, e);
}
- if (conn == null) {
- conn = (HttpURLConnection) url.openConnection();
+
+ if (proxy != null) {
+ client.setProxy(proxy);
+ client.setConnectTimeout(30000, TimeUnit.MILLISECONDS);
+ } else {
+ client.setProxy(Proxy.NO_PROXY);
+ client.setConnectTimeout(5000, TimeUnit.MILLISECONDS);
}
- conn.setConnectTimeout(5000);
- conn.setReadTimeout(25000);
- return conn;
+ client.setReadTimeout(45000, TimeUnit.MILLISECONDS);
+
+ return client;
}
- private String query(String request) throws QueryFailedException, HttpError {
+ private String query(String request, Proxy proxy) throws QueryFailedException, HttpError {
try {
URL url = new URL(getUrlPrefix() + mHost + ":" + mPort + request);
- Log.d(Constants.TAG, "hkp keyserver query: " + url);
- HttpURLConnection conn = openConnection(url);
- conn.connect();
- int response = conn.getResponseCode();
- if (response >= 200 && response < 300) {
- return readAll(conn.getInputStream(), conn.getContentEncoding());
+ Log.d(Constants.TAG, "hkp keyserver query: " + url + " Proxy: " + proxy);
+ OkHttpClient client = getClient(url, proxy);
+ Response response = client.newCall(new Request.Builder().url(url).build()).execute();
+
+ String responseBody = response.body().string();// contains body both in case of success or failure
+
+ if (response.isSuccessful()) {
+ return responseBody;
} else {
- String data = readAll(conn.getErrorStream(), conn.getContentEncoding());
- throw new HttpError(response, data);
+ throw new HttpError(response.code(), responseBody);
}
} catch (IOException e) {
- throw new QueryFailedException("Keyserver '" + mHost + "' is unavailable. Check your Internet connection!");
+ Log.e(Constants.TAG, "IOException at HkpKeyserver", e);
+ throw new QueryFailedException("Keyserver '" + mHost + "' is unavailable. Check your Internet connection!" +
+ proxy == null?"":" Using proxy " + proxy);
}
}
@@ -232,7 +251,7 @@ public class HkpKeyserver extends Keyserver {
* @throws QueryNeedsRepairException
*/
@Override
- public ArrayList<ImportKeysListEntry> search(String query) throws QueryFailedException,
+ public ArrayList<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException,
QueryNeedsRepairException {
ArrayList<ImportKeysListEntry> results = new ArrayList<>();
@@ -250,7 +269,7 @@ public class HkpKeyserver extends Keyserver {
String data;
try {
- data = query(request);
+ data = query(request, proxy);
} catch (HttpError e) {
if (e.getData() != null) {
Log.d(Constants.TAG, "returned error data: " + e.getData().toLowerCase(Locale.ENGLISH));
@@ -334,13 +353,14 @@ public class HkpKeyserver extends Keyserver {
}
@Override
- public String get(String keyIdHex) throws QueryFailedException {
+ public String get(String keyIdHex, Proxy proxy) throws QueryFailedException {
String request = "/pks/lookup?op=get&options=mr&search=" + keyIdHex;
- Log.d(Constants.TAG, "hkp keyserver get: " + request);
+ Log.d(Constants.TAG, "hkp keyserver get: " + request + " using Proxy: " + proxy);
String data;
try {
- data = query(request);
+ data = query(request, proxy);
} catch (HttpError httpError) {
+ Log.e(Constants.TAG, "Failed to get key at HkpKeyserver", httpError);
throw new QueryFailedException("not found");
}
Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data);
@@ -351,38 +371,38 @@ public class HkpKeyserver extends Keyserver {
}
@Override
- public void add(String armoredKey) throws AddKeyException {
+ public void add(String armoredKey, Proxy proxy) throws AddKeyException {
try {
- String request = "/pks/add";
+ String path = "/pks/add";
String params;
try {
params = "keytext=" + URLEncoder.encode(armoredKey, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new AddKeyException();
}
- URL url = new URL(getUrlPrefix() + mHost + ":" + mPort + request);
+ URL url = new URL(getUrlPrefix() + mHost + ":" + mPort + path);
Log.d(Constants.TAG, "hkp keyserver add: " + url.toString());
Log.d(Constants.TAG, "params: " + params);
- HttpURLConnection conn = openConnection(url);
- conn.setRequestMethod("POST");
- conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- conn.setRequestProperty("Content-Length", Integer.toString(params.getBytes().length));
- conn.setDoInput(true);
- conn.setDoOutput(true);
+ RequestBody body = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), params);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .addHeader("Content-Type", "application/x-www-form-urlencoded")
+ .addHeader("Content-Length", Integer.toString(params.getBytes().length))
+ .post(body)
+ .build();
- OutputStream os = conn.getOutputStream();
- BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
- writer.write(params);
- writer.flush();
- writer.close();
- os.close();
+ Response response = getClient(url, proxy).newCall(request).execute();
- conn.connect();
+ Log.d(Constants.TAG, "response code: " + response.code());
+ Log.d(Constants.TAG, "answer: " + response.body().string());
+
+ if (response.code() != 200) {
+ throw new AddKeyException();
+ }
- Log.d(Constants.TAG, "response code: " + conn.getResponseCode());
- Log.d(Constants.TAG, "answer: " + readAll(conn.getInputStream(), conn.getContentEncoding()));
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
throw new AddKeyException();
@@ -398,6 +418,7 @@ public class HkpKeyserver extends Keyserver {
* Tries to find a server responsible for a given domain
*
* @return A responsible Keyserver or null if not found.
+ * TODO: PHILIP Add proxy functionality
*/
public static HkpKeyserver resolve(String domain) {
try {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
index e310e9a3f..c2865410e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
@@ -26,6 +26,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.List;
@@ -34,7 +35,7 @@ public class KeybaseKeyserver extends Keyserver {
private String mQuery;
@Override
- public ArrayList<ImportKeysListEntry> search(String query) throws QueryFailedException,
+ public ArrayList<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException,
QueryNeedsRepairException {
ArrayList<ImportKeysListEntry> results = new ArrayList<>();
@@ -48,7 +49,7 @@ public class KeybaseKeyserver extends Keyserver {
mQuery = query;
try {
- Iterable<Match> matches = Search.search(query);
+ Iterable<Match> matches = Search.search(query, proxy);
for (Match match : matches) {
results.add(makeEntry(match));
}
@@ -98,16 +99,16 @@ public class KeybaseKeyserver extends Keyserver {
}
@Override
- public String get(String id) throws QueryFailedException {
+ public String get(String id, Proxy proxy) throws QueryFailedException {
try {
- return User.keyForUsername(id);
+ return User.keyForUsername(id, proxy);
} catch (KeybaseException e) {
throw new QueryFailedException(e.getMessage());
}
}
@Override
- public void add(String armoredKey) throws AddKeyException {
+ public void add(String armoredKey, Proxy proxy) throws AddKeyException {
throw new AddKeyException();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
index 5e4bd0b70..640b39f44 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
@@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.keyimport;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.Proxy;
import java.util.List;
public abstract class Keyserver {
@@ -31,6 +32,7 @@ public abstract class Keyserver {
public CloudSearchFailureException(String message) {
super(message);
}
+
public CloudSearchFailureException() {
super();
}
@@ -67,12 +69,12 @@ public abstract class Keyserver {
private static final long serialVersionUID = -507574859137295530L;
}
- public abstract List<ImportKeysListEntry> search(String query) throws QueryFailedException,
+ public abstract List<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException,
QueryNeedsRepairException;
- public abstract String get(String keyIdHex) throws QueryFailedException;
+ public abstract String get(String keyIdHex, Proxy proxy) throws QueryFailedException;
- public abstract void add(String armoredKey) throws AddKeyException;
+ public abstract void add(String armoredKey, Proxy proxy) throws AddKeyException;
public static String readAll(InputStream in, String encoding) throws IOException {
ByteArrayOutputStream raw = new ByteArrayOutputStream();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java
index fae59b7a4..e4026eaaf 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java
@@ -19,7 +19,9 @@ package org.sufficientlysecure.keychain.operations;
import android.content.Context;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import org.sufficientlysecure.keychain.Constants.key;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
import org.sufficientlysecure.keychain.pgp.Progressable;
@@ -76,9 +78,8 @@ public abstract class BaseOperation <T extends Parcelable> implements Passphrase
mCancelled = cancelled;
}
- public OperationResult execute(T input, CryptoInputParcel cryptoInput) {
- return null;
- }
+ @NonNull
+ public abstract OperationResult execute(T input, CryptoInputParcel cryptoInput);
public void updateProgress(int message, int current, int total) {
if (mProgressable != null) {
@@ -111,8 +112,11 @@ public abstract class BaseOperation <T extends Parcelable> implements Passphrase
@Override
public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException {
try {
- long masterKeyId = mProviderHelper.getMasterKeyId(subKeyId);
- return getCachedPassphrase(masterKeyId, subKeyId);
+ if (subKeyId != key.symmetric) {
+ long masterKeyId = mProviderHelper.getMasterKeyId(subKeyId);
+ return getCachedPassphrase(masterKeyId, subKeyId);
+ }
+ return getCachedPassphrase(key.symmetric, key.symmetric);
} catch (NotFoundException e) {
throw new PassphraseCacheInterface.NoSecretKeyException();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
index 0806e6a16..eeed24db0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
@@ -18,17 +18,18 @@
package org.sufficientlysecure.keychain.operations;
import android.content.Context;
+import android.support.annotation.NonNull;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
-import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
+import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation;
import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
@@ -43,27 +44,31 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
+import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
-/** An operation which implements a high level user id certification operation.
- *
+/**
+ * An operation which implements a high level user id certification operation.
+ * <p/>
* This operation takes a specific CertifyActionsParcel as its input. These
* contain a masterKeyId to be used for certification, and a list of
* masterKeyIds and related user ids to certify.
*
* @see CertifyActionsParcel
- *
*/
public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
- public CertifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) {
+ public CertifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean
+ cancelled) {
super(context, providerHelper, progressable, cancelled);
}
+ @NonNull
@Override
public CertifyResult execute(CertifyActionsParcel parcel, CryptoInputParcel cryptoInput) {
@@ -86,14 +91,24 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
case PIN:
case PATTERN:
case PASSPHRASE:
- if (!cryptoInput.hasPassphrase()) {
+ passphrase = cryptoInput.getPassphrase();
+ if (passphrase == null) {
+ try {
+ passphrase = getCachedPassphrase(certificationKey.getKeyId(), certificationKey.getKeyId());
+ } catch (PassphraseCacheInterface.NoSecretKeyException ignored) {
+ // treat as a cache miss for error handling purposes
+ }
+ }
+
+ if (passphrase == null) {
return new CertifyResult(log,
RequiredInputParcel.createRequiredSignPassphrase(
- certificationKey.getKeyId(), certificationKey.getKeyId(), null)
+ certificationKey.getKeyId(),
+ certificationKey.getKeyId(),
+ null),
+ cryptoInput
);
}
- // certification is always with the master key id, so use that one
- passphrase = cryptoInput.getPassphrase();
break;
case PASSPHRASE_EMPTY:
@@ -101,6 +116,7 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
break;
case DIVERT_TO_CARD:
+ // the unlock operation will succeed for passphrase == null in a divertToCard key
passphrase = null;
break;
@@ -174,9 +190,9 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
}
- if ( ! allRequiredInput.isEmpty()) {
+ if (!allRequiredInput.isEmpty()) {
log.add(LogType.MSG_CRT_NFC_RETURN, 1);
- return new CertifyResult(log, allRequiredInput.build());
+ return new CertifyResult(log, allRequiredInput.build(), cryptoInput);
}
log.add(LogType.MSG_CRT_SAVING, 1);
@@ -187,11 +203,24 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
return new CertifyResult(CertifyResult.RESULT_CANCELLED, log);
}
+ // these variables are used inside the following loop, but they need to be created only once
HkpKeyserver keyServer = null;
ExportOperation exportOperation = null;
+ Proxy proxy = null;
if (parcel.keyServerUri != null) {
keyServer = new HkpKeyserver(parcel.keyServerUri);
exportOperation = new ExportOperation(mContext, mProviderHelper, mProgressable);
+ if (cryptoInput.getParcelableProxy() == null) {
+ // explicit proxy not set
+ if (!OrbotHelper.isOrbotInRequiredState(mContext)) {
+ return new CertifyResult(null,
+ RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
+ }
+ proxy = Preferences.getPreferences(mContext).getProxyPrefs()
+ .parcelableProxy.getProxy();
+ } else {
+ proxy = cryptoInput.getParcelableProxy().getProxy();
+ }
}
// Write all certified keys into the database
@@ -200,7 +229,8 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
// Check if we were cancelled
if (checkCancelled()) {
log.add(LogType.MSG_OPERATION_CANCELLED, 0);
- return new CertifyResult(CertifyResult.RESULT_CANCELLED, log, certifyOk, certifyError, uploadOk, uploadError);
+ return new CertifyResult(CertifyResult.RESULT_CANCELLED, log, certifyOk, certifyError, uploadOk,
+ uploadError);
}
log.add(LogType.MSG_CRT_SAVE, 2,
@@ -210,12 +240,15 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
SaveKeyringResult result = mProviderHelper.savePublicKeyRing(certifiedKey);
if (exportOperation != null) {
- // TODO use subresult, get rid of try/catch!
- try {
- exportOperation.uploadKeyRingToServer(keyServer, certifiedKey);
+ ExportResult uploadResult = exportOperation.uploadKeyRingToServer(
+ keyServer,
+ certifiedKey,
+ proxy);
+ log.add(uploadResult, 2);
+
+ if (uploadResult.success()) {
uploadOk += 1;
- } catch (AddKeyException e) {
- Log.e(Constants.TAG, "error uploading key", e);
+ } else {
uploadError += 1;
}
}
@@ -227,19 +260,24 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
}
log.add(result, 2);
-
}
if (certifyOk == 0) {
log.add(LogType.MSG_CRT_ERROR_NOTHING, 0);
- return new CertifyResult(CertifyResult.RESULT_ERROR, log, certifyOk, certifyError, uploadOk, uploadError);
+ return new CertifyResult(CertifyResult.RESULT_ERROR, log, certifyOk, certifyError,
+ uploadOk, uploadError);
}
- log.add(LogType.MSG_CRT_SUCCESS, 0);
- //since only verified keys are synced to contacts, we need to initiate a sync now
+ // since only verified keys are synced to contacts, we need to initiate a sync now
ContactSyncAdapterService.requestSync();
-
- return new CertifyResult(CertifyResult.RESULT_OK, log, certifyOk, certifyError, uploadOk, uploadError);
+
+ log.add(LogType.MSG_CRT_SUCCESS, 0);
+ if (uploadError != 0) {
+ return new CertifyResult(CertifyResult.RESULT_WARNINGS, log, certifyOk, certifyError, uploadOk,
+ uploadError);
+ } else {
+ return new CertifyResult(CertifyResult.RESULT_OK, log, certifyOk, certifyError, uploadOk, uploadError);
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java
index bda574e0a..782cd6800 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java
@@ -20,6 +20,7 @@
package org.sufficientlysecure.keychain.operations;
import android.content.Context;
+import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
@@ -34,6 +35,7 @@ public class ConsolidateOperation extends BaseOperation<ConsolidateInputParcel>
super(context, providerHelper, progressable);
}
+ @NonNull
@Override
public ConsolidateResult execute(ConsolidateInputParcel consolidateInputParcel,
CryptoInputParcel cryptoInputParcel) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java
index 50b2ef69b..56bd3b786 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java
@@ -18,9 +18,11 @@
package org.sufficientlysecure.keychain.operations;
import android.content.Context;
+import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.pgp.Progressable;
@@ -45,13 +47,19 @@ public class DeleteOperation extends BaseOperation<DeleteKeyringParcel> {
super(context, providerHelper, progressable);
}
+ @NonNull
@Override
- public DeleteResult execute(DeleteKeyringParcel deleteKeyringParcel,
+ public OperationResult execute(DeleteKeyringParcel deleteKeyringParcel,
CryptoInputParcel cryptoInputParcel) {
long[] masterKeyIds = deleteKeyringParcel.mMasterKeyIds;
boolean isSecret = deleteKeyringParcel.mIsSecret;
+ return onlyDeleteKey(masterKeyIds, isSecret);
+ }
+
+ private DeleteResult onlyDeleteKey(long[] masterKeyIds, boolean isSecret) {
+
OperationLog log = new OperationLog();
if (masterKeyIds.length == 0) {
@@ -111,7 +119,6 @@ public class DeleteOperation extends BaseOperation<DeleteKeyringParcel> {
}
return new DeleteResult(result, log, success, fail);
-
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
index da0aef018..f5ba88502 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
@@ -18,10 +18,12 @@
package org.sufficientlysecure.keychain.operations;
import android.content.Context;
+import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
-import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.operations.results.ExportResult;
+import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
@@ -33,16 +35,20 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
+import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ProgressScaler;
+import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
-/** An operation which implements a high level key edit operation.
- *
+/**
+ * An operation which implements a high level key edit operation.
+ * <p/>
* This operation provides a higher level interface to the edit and
* create key operations in PgpKeyOperation. It takes care of fetching
* and saving the key before and after the operation.
@@ -57,7 +63,16 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
super(context, providerHelper, progressable, cancelled);
}
- public OperationResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) {
+ /**
+ * Saves an edited key, and uploads it to a server atomically or otherwise as
+ * specified in saveParcel
+ *
+ * @param saveParcel primary input to the operation
+ * @param cryptoInput input that changes if user interaction is required
+ * @return the result of the operation
+ */
+ @NonNull
+ public InputPendingResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) {
OperationLog log = new OperationLog();
log.add(LogType.MSG_ED, 0);
@@ -118,6 +133,36 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
// It's a success, so this must be non-null now
UncachedKeyRing ring = modifyResult.getRing();
+ if (saveParcel.isUpload()) {
+ UncachedKeyRing publicKeyRing;
+ try {
+ publicKeyRing = ring.extractPublicKeyRing();
+ } catch (IOException e) {
+ log.add(LogType.MSG_ED_ERROR_EXTRACTING_PUBLIC_UPLOAD, 1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ ExportKeyringParcel exportKeyringParcel =
+ new ExportKeyringParcel(saveParcel.getUploadKeyserver(),
+ publicKeyRing);
+
+ ExportResult uploadResult =
+ new ExportOperation(mContext, mProviderHelper, mProgressable)
+ .execute(exportKeyringParcel, cryptoInput);
+
+ if (uploadResult.isPending()) {
+ return uploadResult;
+ } else if (!uploadResult.success() && saveParcel.isUploadAtomic()) {
+ // if atomic, update fail implies edit operation should also fail and not save
+ log.add(uploadResult, 2);
+ return new EditKeyResult(log, RequiredInputParcel.createRetryUploadOperation(),
+ cryptoInput);
+ } else {
+ // upload succeeded or not atomic so we continue
+ log.add(uploadResult, 2);
+ }
+ }
+
// Save the new keyring.
SaveKeyringResult saveResult = mProviderHelper
.saveSecretKeyRing(ring, new ProgressScaler(mProgressable, 60, 95, 100));
@@ -129,15 +174,24 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
}
// There is a new passphrase - cache it
- if (saveParcel.mNewUnlock != null) {
+ if (saveParcel.mNewUnlock != null && cryptoInput.mCachePassphrase) {
log.add(LogType.MSG_ED_CACHING_NEW, 1);
- PassphraseCacheService.addCachedPassphrase(mContext,
- ring.getMasterKeyId(),
- ring.getMasterKeyId(),
- saveParcel.mNewUnlock.mNewPassphrase != null
- ? saveParcel.mNewUnlock.mNewPassphrase
- : saveParcel.mNewUnlock.mNewPin,
- ring.getPublicKey().getPrimaryUserIdWithFallback());
+
+ // NOTE: Don't cache empty passphrases! Important for MOVE_KEY_TO_CARD
+ if (saveParcel.mNewUnlock.mNewPassphrase != null
+ && ( ! saveParcel.mNewUnlock.mNewPassphrase.isEmpty())) {
+ PassphraseCacheService.addCachedPassphrase(mContext,
+ ring.getMasterKeyId(),
+ ring.getMasterKeyId(),
+ saveParcel.mNewUnlock.mNewPassphrase,
+ ring.getPublicKey().getPrimaryUserIdWithFallback());
+ } else if (saveParcel.mNewUnlock.mNewPin != null) {
+ PassphraseCacheService.addCachedPassphrase(mContext,
+ ring.getMasterKeyId(),
+ ring.getMasterKeyId(),
+ saveParcel.mNewUnlock.mNewPin,
+ ring.getPublicKey().getPrimaryUserIdWithFallback());
+ }
}
updateProgress(R.string.progress_done, 100, 100);
@@ -149,5 +203,4 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
return new EditKeyResult(EditKeyResult.RESULT_OK, log, ring.getMasterKeyId());
}
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java
index 01a45bc79..a5b70a41f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java
@@ -18,9 +18,22 @@
package org.sufficientlysecure.keychain.operations;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Proxy;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.Constants;
@@ -40,18 +53,12 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.concurrent.atomic.AtomicBoolean;
+import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
/**
* An operation class which implements high level export
@@ -62,7 +69,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries()
* For the export operation, the input consists of a set of key ids and
* either the name of a file or an output uri to write to.
- * TODO rework uploadKeyRingToServer
*/
public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
@@ -76,26 +82,43 @@ public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
super(context, providerHelper, progressable, cancelled);
}
- public void uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring)
- throws AddKeyException {
- uploadKeyRingToServer(server, keyring.getUncachedKeyRing());
+ public ExportResult uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring,
+ Proxy proxy) {
+ return uploadKeyRingToServer(server, keyring.getUncachedKeyRing(), proxy);
}
- public void uploadKeyRingToServer(HkpKeyserver server, UncachedKeyRing keyring) throws
- AddKeyException {
+ public ExportResult uploadKeyRingToServer(HkpKeyserver server, UncachedKeyRing keyring, Proxy proxy) {
+ mProgressable.setProgress(R.string.progress_uploading, 0, 1);
+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
+ OperationLog log = new OperationLog();
+ log.add(LogType.MSG_EXPORT_UPLOAD_PUBLIC, 0, KeyFormattingUtils.convertKeyIdToHex(
+ keyring.getPublicKey().getKeyId()
+ ));
+
try {
aos = new ArmoredOutputStream(bos);
keyring.encode(aos);
aos.close();
String armoredKey = bos.toString("UTF-8");
- server.add(armoredKey);
+ server.add(armoredKey, proxy);
+
+ log.add(LogType.MSG_EXPORT_UPLOAD_SUCCESS, 1);
+ return new ExportResult(ExportResult.RESULT_OK, log);
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
- throw new AddKeyException();
+
+ log.add(LogType.MSG_EXPORT_ERROR_KEY, 1);
+ return new ExportResult(ExportResult.RESULT_ERROR, log);
+ } catch (AddKeyException e) {
+ Log.e(Constants.TAG, "AddKeyException", e);
+
+ log.add(LogType.MSG_EXPORT_ERROR_UPLOAD, 1);
+ return new ExportResult(ExportResult.RESULT_ERROR, log);
} finally {
+ mProgressable.setProgress(R.string.progress_uploading, 1, 1);
try {
if (aos != null) {
aos.close();
@@ -192,21 +215,21 @@ public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
Cursor cursor = null;
try {
- String selection = null, ids[] = null;
+ String selection = null, selectionArgs[] = null;
if (masterKeyIds != null) {
- // generate placeholders and string selection args
- ids = new String[masterKeyIds.length];
- StringBuilder placeholders = new StringBuilder("?");
+ // convert long[] to String[]
+ selectionArgs = new String[masterKeyIds.length];
for (int i = 0; i < masterKeyIds.length; i++) {
- ids[i] = Long.toString(masterKeyIds[i]);
- if (i != 0) {
- placeholders.append(",?");
- }
+ selectionArgs[i] = Long.toString(masterKeyIds[i]);
}
+ // generates ?,?,? as placeholders for selectionArgs
+ String placeholders = TextUtils.join(",",
+ Collections.nCopies(masterKeyIds.length, "?"));
+
// put together selection string
- selection = Tables.KEY_RINGS_PUBLIC + "." + KeyRings.MASTER_KEY_ID
+ selection = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
+ " IN (" + placeholders + ")";
}
@@ -214,7 +237,7 @@ public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
KeyRings.buildUnifiedKeyRingsUri(), new String[]{
KeyRings.MASTER_KEY_ID, KeyRings.PUBKEY_DATA,
KeyRings.PRIVKEY_DATA, KeyRings.HAS_ANY_SECRET
- }, selection, ids, Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
+ }, selection, selectionArgs, Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
);
if (cursor == null || !cursor.moveToFirst()) {
@@ -311,20 +334,37 @@ public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
}
+ @NonNull
public ExportResult execute(ExportKeyringParcel exportInput, CryptoInputParcel cryptoInput) {
switch (exportInput.mExportType) {
case UPLOAD_KEYSERVER: {
+ Proxy proxy;
+ if (cryptoInput.getParcelableProxy() == null) {
+ // explicit proxy not set
+ if (!OrbotHelper.isOrbotInRequiredState(mContext)) {
+ return new ExportResult(null,
+ RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
+ }
+ proxy = Preferences.getPreferences(mContext).getProxyPrefs()
+ .parcelableProxy.getProxy();
+ } else {
+ proxy = cryptoInput.getParcelableProxy().getProxy();
+ }
+
HkpKeyserver hkpKeyserver = new HkpKeyserver(exportInput.mKeyserver);
try {
- CanonicalizedPublicKeyRing keyring
- = mProviderHelper.getCanonicalizedPublicKeyRing(
- exportInput.mCanonicalizedPublicKeyringUri);
- uploadKeyRingToServer(hkpKeyserver, keyring);
- // TODO: replace with proper log
- return new ExportResult(ExportResult.RESULT_OK, new OperationLog());
- } catch (Exception e) {
+ if (exportInput.mCanonicalizedPublicKeyringUri != null) {
+ CanonicalizedPublicKeyRing keyring
+ = mProviderHelper.getCanonicalizedPublicKeyRing(
+ exportInput.mCanonicalizedPublicKeyringUri);
+ return uploadKeyRingToServer(hkpKeyserver, keyring, proxy);
+ } else {
+ return uploadKeyRingToServer(hkpKeyserver, exportInput.mUncachedKeyRing,
+ proxy);
+ }
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.e(Constants.TAG, "error uploading key", e);
return new ExportResult(ExportResult.RESULT_ERROR, new OperationLog());
- // TODO: Implement better exception handling, replace with log
}
}
case EXPORT_FILE: {
@@ -335,8 +375,8 @@ public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
return exportToUri(exportInput.mMasterKeyIds, exportInput.mExportSecret,
exportInput.mOutputUri);
}
- default: { // can't happen
- return null;
+ default: { // can never happen, all enum types must be handled above
+ throw new AssertionError("must not happen, this is a bug!");
}
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
index ace059dac..4acfd6e30 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
@@ -18,7 +18,24 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import android.content.Context;
+import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -39,24 +56,13 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize;
+import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.ProgressScaler;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
/**
* An operation class which implements high level import
@@ -89,39 +95,40 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
// Overloaded functions for using progressable supplied in constructor during import
public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
- String keyServerUri) {
- return serialKeyRingImport(entries, num, keyServerUri, mProgressable);
+ String keyServerUri, Proxy proxy) {
+ return serialKeyRingImport(entries, num, keyServerUri, mProgressable, proxy);
}
public ImportKeyResult serialKeyRingImport(List<ParcelableKeyRing> entries,
- String keyServerUri) {
+ String keyServerUri, Proxy proxy) {
Iterator<ParcelableKeyRing> it = entries.iterator();
int numEntries = entries.size();
- return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable);
+ return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable, proxy);
}
public ImportKeyResult serialKeyRingImport(List<ParcelableKeyRing> entries, String keyServerUri,
- Progressable progressable) {
+ Progressable progressable, Proxy proxy) {
Iterator<ParcelableKeyRing> it = entries.iterator();
int numEntries = entries.size();
- return serialKeyRingImport(it, numEntries, keyServerUri, progressable);
+ return serialKeyRingImport(it, numEntries, keyServerUri, progressable, proxy);
}
+ @NonNull
public ImportKeyResult serialKeyRingImport(ParcelableFileCache<ParcelableKeyRing> cache,
- String keyServerUri) {
+ String keyServerUri, Proxy proxy) {
// get entries from cached file
try {
IteratorWithSize<ParcelableKeyRing> it = cache.readCache();
int numEntries = it.getSize();
- return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable);
+ return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable, proxy);
} catch (IOException e) {
// Special treatment here, we need a lot
@@ -143,11 +150,14 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
* @param keyServerUri contains uri of keyserver to import from, if it is an import from cloud
* @param progressable Allows multi-threaded import to supply a progressable that ignores the
* progress of a single key being imported
- * @return
*/
+ @NonNull
public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
- String keyServerUri, Progressable progressable) {
- updateProgress(R.string.progress_importing, 0, 100);
+ String keyServerUri, Progressable progressable,
+ Proxy proxy) {
+ if (progressable != null) {
+ progressable.setProgress(R.string.progress_importing, 0, 100);
+ }
OperationLog log = new OperationLog();
log.add(LogType.MSG_IMPORT, 0, num);
@@ -208,10 +218,11 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
if (entry.mExpectedFingerprint != null) {
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" +
entry.mExpectedFingerprint.substring(24));
- data = keyServer.get("0x" + entry.mExpectedFingerprint).getBytes();
+ data = keyServer.get("0x" + entry.mExpectedFingerprint, proxy)
+ .getBytes();
} else {
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, entry.mKeyIdHex);
- data = keyServer.get(entry.mKeyIdHex).getBytes();
+ data = keyServer.get(entry.mKeyIdHex, proxy).getBytes();
}
key = UncachedKeyRing.decodeFromData(data);
if (key != null) {
@@ -234,7 +245,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
try {
log.add(LogType.MSG_IMPORT_FETCH_KEYBASE, 2, entry.mKeybaseName);
- byte[] data = keybaseServer.get(entry.mKeybaseName).getBytes();
+ byte[] data = keybaseServer.get(entry.mKeybaseName, proxy).getBytes();
UncachedKeyRing keybaseKey = UncachedKeyRing.decodeFromData(data);
// If there already is a key, merge the two
@@ -373,12 +384,11 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
importedMasterKeyIdsArray);
}
+ @NonNull
@Override
- public ImportKeyResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) {
- return importKeys(importInput.mKeyList, importInput.mKeyserver);
- }
-
- public ImportKeyResult importKeys(ArrayList<ParcelableKeyRing> keyList, String keyServer) {
+ public OperationResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) {
+ ArrayList<ParcelableKeyRing> keyList = importInput.mKeyList;
+ String keyServer = importInput.mKeyserver;
ImportKeyResult result;
@@ -386,8 +396,21 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
ParcelableFileCache<ParcelableKeyRing> cache = new ParcelableFileCache<>(mContext,
"key_import.pcl");
- result = serialKeyRingImport(cache, keyServer);
+ result = serialKeyRingImport(cache, null, null);
} else {
+ Proxy proxy;
+ if (cryptoInput.getParcelableProxy() == null) {
+ // explicit proxy not set
+ if(!OrbotHelper.isOrbotInRequiredState(mContext)) {
+ // show dialog to enable/install dialog
+ return new ImportKeyResult(null,
+ RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
+ }
+ proxy = Preferences.getPreferences(mContext).getProxyPrefs().parcelableProxy
+ .getProxy();
+ } else {
+ proxy = cryptoInput.getParcelableProxy().getProxy();
+ }
// if there is more than one key with the same fingerprint, we do a serial import to
// prevent
// https://github.com/open-keychain/open-keychain/issues/1221
@@ -397,9 +420,10 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
}
if (keyFingerprintSet.size() == keyList.size()) {
// all keys have unique fingerprints
- result = multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer);
+ result = multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer,
+ proxy);
} else {
- result = serialKeyRingImport(keyList, keyServer);
+ result = serialKeyRingImport(keyList, keyServer, proxy);
}
}
@@ -407,8 +431,10 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
return result;
}
+ @NonNull
private ImportKeyResult multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator,
- int totKeys, final String keyServer) {
+ int totKeys, final String keyServer,
+ final Proxy proxy) {
Log.d(Constants.TAG, "Multi-threaded key import starting");
if (keyListIterator != null) {
KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable);
@@ -421,7 +447,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
new SynchronousQueue<Runnable>());
ExecutorCompletionService<ImportKeyResult> importCompletionService =
- new ExecutorCompletionService(importExecutor);
+ new ExecutorCompletionService<>(importExecutor);
while (keyListIterator.hasNext()) { // submit all key rings to be imported
@@ -436,7 +462,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
ArrayList<ParcelableKeyRing> list = new ArrayList<>();
list.add(pkRing);
- return serialKeyRingImport(list, keyServer, ignoreProgressable);
+ return serialKeyRingImport(list, keyServer, ignoreProgressable, proxy);
}
};
@@ -562,4 +588,4 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
}
}
-} \ No newline at end of file
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java
index 57b99951d..30f37dd4f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java
@@ -19,7 +19,15 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+
import android.content.Context;
+import android.support.annotation.NonNull;
import com.textuality.keybase.lib.Proof;
import com.textuality.keybase.lib.prover.Prover;
@@ -41,11 +49,9 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificationParcel> {
@@ -54,9 +60,22 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat
super(context, providerHelper, progressable);
}
+ @NonNull
@Override
public KeybaseVerificationResult execute(KeybaseVerificationParcel keybaseInput,
CryptoInputParcel cryptoInput) {
+ Proxy proxy;
+ if (cryptoInput.getParcelableProxy() == null) {
+ // explicit proxy not set
+ if (!OrbotHelper.isOrbotInRequiredState(mContext)) {
+ return new KeybaseVerificationResult(null,
+ RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
+ }
+ proxy = Preferences.getPreferences(mContext).getProxyPrefs()
+ .parcelableProxy.getProxy();
+ } else {
+ proxy = cryptoInput.getParcelableProxy().getProxy();
+ }
String requiredFingerprint = keybaseInput.mRequiredFingerprint;
@@ -76,7 +95,7 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
- if (!prover.fetchProofData()) {
+ if (!prover.fetchProofData(proxy)) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FETCH_PROOF, 1);
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
@@ -96,7 +115,7 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
Record[] records = dnsQuery.getAnswers();
- List<List<byte[]>> extents = new ArrayList<List<byte[]>>();
+ List<List<byte[]>> extents = new ArrayList<>();
for (Record r : records) {
Data d = r.getPayload();
if (d instanceof TXT) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java
index efe0c466a..2f25b6926 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java
@@ -17,7 +17,11 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
import android.content.Context;
+import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
@@ -29,7 +33,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
-import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
@@ -37,9 +40,6 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ProgressScaler;
-import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicBoolean;
-
/** An operation which promotes a public key ring to a secret one.
*
* This operation can only be applied to public key rings where no secret key
@@ -54,18 +54,10 @@ public class PromoteKeyOperation extends BaseOperation<PromoteKeyringParcel> {
super(context, providerHelper, progressable, cancelled);
}
+ @NonNull
@Override
public PromoteKeyResult execute(PromoteKeyringParcel promoteKeyringParcel,
CryptoInputParcel cryptoInputParcel) {
- // Input
- long masterKeyId = promoteKeyringParcel.mKeyRingId;
- byte[] cardAid = promoteKeyringParcel.mCardAid;
- long[] subKeyIds = promoteKeyringParcel.mSubKeyIds;
-
- return execute(masterKeyId, cardAid, subKeyIds);
- }
-
- public PromoteKeyResult execute(long masterKeyId, byte[] cardAid, long[] subKeyIds) {
OperationLog log = new OperationLog();
log.add(LogType.MSG_PR, 0);
@@ -76,17 +68,17 @@ public class PromoteKeyOperation extends BaseOperation<PromoteKeyringParcel> {
try {
log.add(LogType.MSG_PR_FETCHING, 1,
- KeyFormattingUtils.convertKeyIdToHex(masterKeyId));
+ KeyFormattingUtils.convertKeyIdToHex(promoteKeyringParcel.mKeyRingId));
CanonicalizedPublicKeyRing pubRing =
- mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId);
+ mProviderHelper.getCanonicalizedPublicKeyRing(promoteKeyringParcel.mKeyRingId);
- if (subKeyIds == null) {
+ if (promoteKeyringParcel.mSubKeyIds == null) {
log.add(LogType.MSG_PR_ALL, 1);
} else {
// sort for binary search
for (CanonicalizedPublicKey key : pubRing.publicKeyIterator()) {
long subKeyId = key.getKeyId();
- if (naiveIndexOf(subKeyIds, subKeyId) != null) {
+ if (naiveIndexOf(promoteKeyringParcel.mSubKeyIds, subKeyId) != null) {
log.add(LogType.MSG_PR_SUBKEY_MATCH, 1,
KeyFormattingUtils.convertKeyIdToHex(subKeyId));
} else {
@@ -97,7 +89,8 @@ public class PromoteKeyOperation extends BaseOperation<PromoteKeyringParcel> {
}
// create divert-to-card secret key from public key
- promotedRing = pubRing.createDivertSecretRing(cardAid, subKeyIds);
+ promotedRing = pubRing.createDivertSecretRing(promoteKeyringParcel.mCardAid,
+ promoteKeyringParcel.mSubKeyIds);
} catch (NotFoundException e) {
log.add(LogType.MSG_PR_ERROR_KEY_NOT_FOUND, 2);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java
new file mode 100644
index 000000000..ecf64e1af
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@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
+ * 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.operations;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.operations.results.RevokeResult;
+import org.sufficientlysecure.keychain.pgp.Progressable;
+import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
+import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.RevokeKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.util.Log;
+
+public class RevokeOperation extends BaseOperation<RevokeKeyringParcel> {
+
+ public RevokeOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
+ super(context, providerHelper, progressable);
+ }
+
+ @NonNull
+ @Override
+ public OperationResult execute(RevokeKeyringParcel revokeKeyringParcel,
+ CryptoInputParcel cryptoInputParcel) {
+
+ // we don't cache passphrases during revocation
+ cryptoInputParcel.mCachePassphrase = false;
+
+ long masterKeyId = revokeKeyringParcel.mMasterKeyId;
+
+ OperationResult.OperationLog log = new OperationResult.OperationLog();
+ log.add(OperationResult.LogType.MSG_REVOKE, 0,
+ KeyFormattingUtils.beautifyKeyId(masterKeyId));
+
+ try {
+
+ Uri secretUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(masterKeyId);
+ CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing(secretUri);
+
+ // check if this is a master secret key we can work with
+ switch (keyRing.getSecretKeyType(masterKeyId)) {
+ case GNU_DUMMY:
+ log.add(OperationResult.LogType.MSG_EK_ERROR_DUMMY, 1);
+ return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId);
+ }
+
+ SaveKeyringParcel saveKeyringParcel = getRevokedSaveKeyringParcel(masterKeyId,
+ keyRing.getFingerprint());
+
+ // all revoke operations are made atomic as of now
+ saveKeyringParcel.setUpdateOptions(revokeKeyringParcel.mUpload, true,
+ revokeKeyringParcel.mKeyserver);
+
+ InputPendingResult revokeAndUploadResult = new EditKeyOperation(mContext,
+ mProviderHelper, mProgressable, mCancelled)
+ .execute(saveKeyringParcel, cryptoInputParcel);
+
+ if (revokeAndUploadResult.isPending()) {
+ return revokeAndUploadResult;
+ }
+
+ log.add(revokeAndUploadResult, 1);
+
+ if (revokeAndUploadResult.success()) {
+ log.add(OperationResult.LogType.MSG_REVOKE_OK, 1);
+ return new RevokeResult(RevokeResult.RESULT_OK, log, masterKeyId);
+ } else {
+ log.add(OperationResult.LogType.MSG_REVOKE_KEY_FAIL, 1);
+ return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId);
+ }
+
+ } catch (PgpKeyNotFoundException | ProviderHelper.NotFoundException e) {
+ Log.e(Constants.TAG, "could not find key to revoke", e);
+ log.add(OperationResult.LogType.MSG_REVOKE_KEY_FAIL, 1);
+ return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId);
+ }
+ }
+
+ private SaveKeyringParcel getRevokedSaveKeyringParcel(long masterKeyId, byte[] fingerprint) {
+ final String[] SUBKEYS_PROJECTION = new String[]{
+ KeychainContract.Keys.KEY_ID
+ };
+ final int INDEX_KEY_ID = 0;
+
+ Uri keysUri = KeychainContract.Keys.buildKeysUri(masterKeyId);
+ Cursor subKeyCursor =
+ mContext.getContentResolver().query(keysUri, SUBKEYS_PROJECTION, null, null, null);
+
+ SaveKeyringParcel saveKeyringParcel =
+ new SaveKeyringParcel(masterKeyId, fingerprint);
+
+ // add all subkeys, for revocation
+ while (subKeyCursor != null && subKeyCursor.moveToNext()) {
+ saveKeyringParcel.mRevokeSubKeys.add(subKeyCursor.getLong(INDEX_KEY_ID));
+ }
+ if (subKeyCursor != null) {
+ subKeyCursor.close();
+ }
+
+ final String[] USER_IDS_PROJECTION = new String[]{
+ KeychainContract.UserPackets.USER_ID
+ };
+ final int INDEX_USER_ID = 0;
+
+ Uri userIdsUri = KeychainContract.UserPackets.buildUserIdsUri(masterKeyId);
+ Cursor userIdCursor = mContext.getContentResolver().query(
+ userIdsUri, USER_IDS_PROJECTION, null, null, null);
+
+ while (userIdCursor != null && userIdCursor.moveToNext()) {
+ saveKeyringParcel.mRevokeUserIds.add(userIdCursor.getString(INDEX_USER_ID));
+ }
+ if (userIdCursor != null) {
+ userIdCursor.close();
+ }
+
+ return saveKeyringParcel;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java
index 7c58d62f8..843a55389 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java
@@ -19,13 +19,13 @@ package org.sufficientlysecure.keychain.operations;
import android.content.Context;
import android.net.Uri;
+import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
-import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSign
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.InputData;
+import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.ByteArrayInputStream;
@@ -62,6 +63,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
super(context, providerHelper, progressable, cancelled);
}
+ @NonNull
public SignEncryptResult execute(SignEncryptParcel input, CryptoInputParcel cryptoInput) {
OperationLog log = new OperationLog();
@@ -85,7 +87,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
input.getSignatureMasterKeyId()).getSecretSignId();
input.setSignatureSubKeyId(signKeyId);
} catch (PgpKeyNotFoundException e) {
- e.printStackTrace();
+ Log.e(Constants.TAG, "Key not found", e);
return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results);
}
}
@@ -153,7 +155,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
RequiredInputParcel requiredInput = result.getRequiredInputParcel();
// Passphrase returns immediately, nfc are aggregated
if (requiredInput.mType == RequiredInputType.PASSPHRASE) {
- return new SignEncryptResult(log, requiredInput, results);
+ return new SignEncryptResult(log, requiredInput, results, cryptoInput);
}
if (pendingInputBuilder == null) {
pendingInputBuilder = new NfcSignOperationsBuilder(requiredInput.mSignatureTime,
@@ -171,7 +173,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
} while (!inputUris.isEmpty());
if (pendingInputBuilder != null && !pendingInputBuilder.isEmpty()) {
- return new SignEncryptResult(log, pendingInputBuilder.build(), results);
+ return new SignEncryptResult(log, pendingInputBuilder.build(), results, cryptoInput);
}
if (!outputUris.isEmpty()) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java
index a9f8170d9..cf73f019c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.os.Parcel;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
@@ -38,8 +39,9 @@ public class CertifyResult extends InputPendingResult {
super(result, log);
}
- public CertifyResult(OperationLog log, RequiredInputParcel requiredInput) {
- super(log, requiredInput);
+ public CertifyResult(OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
}
public CertifyResult(int result, OperationLog log, int certifyOk, int certifyError, int uploadOk, int uploadError) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java
index 25a86f137..f9a738d56 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java
@@ -24,7 +24,6 @@ import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
-import org.sufficientlysecure.keychain.util.Passphrase;
public class DecryptVerifyResult extends InputPendingResult {
@@ -45,8 +44,9 @@ public class DecryptVerifyResult extends InputPendingResult {
super(result, log);
}
- public DecryptVerifyResult(OperationLog log, RequiredInputParcel requiredInput) {
- super(log, requiredInput);
+ public DecryptVerifyResult(OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
}
public DecryptVerifyResult(Parcel source) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java
index 52ff8bf44..1a8f10d4f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java
@@ -21,8 +21,11 @@ package org.sufficientlysecure.keychain.operations.results;
import android.app.Activity;
import android.content.Intent;
import android.os.Parcel;
+import android.support.annotation.Nullable;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -30,7 +33,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Showable;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
-public class DeleteResult extends OperationResult {
+public class DeleteResult extends InputPendingResult {
final public int mOk, mFail;
@@ -40,6 +43,19 @@ public class DeleteResult extends OperationResult {
mFail = fail;
}
+ /**
+ * used when more input is required
+ * @param log operation log upto point of required input, if any
+ * @param requiredInput represents input required
+ */
+ public DeleteResult(@Nullable OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
+ // values are not to be used
+ mOk = -1;
+ mFail = -1;
+ }
+
/** Construct from a parcel - trivial because we have no extra data. */
public DeleteResult(Parcel source) {
super(source);
@@ -109,7 +125,10 @@ public class DeleteResult extends OperationResult {
} else {
duration = 0;
style = Style.ERROR;
- if (mFail == 0) {
+ if (mLog.getLast().mType == LogType.MSG_DEL_ERROR_MULTI_SECRET) {
+ str = activity.getString(R.string.secret_cannot_multiple);
+ }
+ else if (mFail == 0) {
str = activity.getString(R.string.delete_nothing);
} else {
str = activity.getResources().getQuantityString(R.plurals.delete_fail, mFail);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java
index 842b75c3b..6098d59d5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java
@@ -20,7 +20,10 @@ package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel;
-public class EditKeyResult extends OperationResult {
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+
+public class EditKeyResult extends InputPendingResult {
public final Long mMasterKeyId;
@@ -29,6 +32,12 @@ public class EditKeyResult extends OperationResult {
mMasterKeyId = masterKeyId;
}
+ public EditKeyResult(OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
+ mMasterKeyId = null;
+ }
+
public EditKeyResult(Parcel source) {
super(source);
mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java
index c8edce259..e21ef949f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java
@@ -19,7 +19,10 @@ package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel;
-public class ExportResult extends OperationResult {
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+
+public class ExportResult extends InputPendingResult {
final int mOkPublic, mOkSecret;
@@ -33,6 +36,15 @@ public class ExportResult extends OperationResult {
mOkSecret = okSecret;
}
+
+ public ExportResult(OperationLog log, RequiredInputParcel requiredInputParcel,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInputParcel, cryptoInputParcel);
+ // we won't use these values
+ mOkPublic = -1;
+ mOkSecret = -1;
+ }
+
/** Construct from a parcel - trivial because we have no extra data. */
public ExportResult(Parcel source) {
super(source);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java
index 53bc545c5..bdc4d9a47 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java
@@ -20,7 +20,10 @@ package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel;
-public class GetKeyResult extends OperationResult {
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+
+public class GetKeyResult extends InputPendingResult {
public int mNonPgpPartsCount;
@@ -36,6 +39,11 @@ public class GetKeyResult extends OperationResult {
super(result, log);
}
+ public GetKeyResult(OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
+ }
+
public static final int RESULT_ERROR_NO_VALID_KEYS = RESULT_ERROR + 8;
public static final int RESULT_ERROR_NO_PGP_PARTS = RESULT_ERROR + 16;
public static final int RESULT_ERROR_QUERY_TOO_SHORT = RESULT_ERROR + 32;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java
index 2a032cef2..5f5090bee 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java
@@ -23,6 +23,8 @@ import android.content.Intent;
import android.os.Parcel;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -30,7 +32,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Showable;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
-public class ImportKeyResult extends OperationResult {
+public class ImportKeyResult extends InputPendingResult {
public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;
public final long[] mImportedMasterKeyIds;
@@ -80,7 +82,7 @@ public class ImportKeyResult extends OperationResult {
}
public ImportKeyResult(int result, OperationLog log) {
- this(result, log, 0, 0, 0, 0, new long[] { });
+ this(result, log, 0, 0, 0, 0, new long[]{});
}
public ImportKeyResult(int result, OperationLog log,
@@ -94,6 +96,17 @@ public class ImportKeyResult extends OperationResult {
mImportedMasterKeyIds = importedMasterKeyIds;
}
+ public ImportKeyResult(OperationLog log, RequiredInputParcel requiredInputParcel,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInputParcel, cryptoInputParcel);
+ // just assign default values, we won't use them anyway
+ mNewKeys = 0;
+ mUpdatedKeys = 0;
+ mBadKeys = 0;
+ mSecret = 0;
+ mImportedMasterKeyIds = new long[]{};
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
index 0b7aa6d03..d767382ae 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
@@ -18,10 +18,9 @@
package org.sufficientlysecure.keychain.operations.results;
-import java.util.ArrayList;
-
import android.os.Parcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
public class InputPendingResult extends OperationResult {
@@ -30,26 +29,33 @@ public class InputPendingResult extends OperationResult {
public static final int RESULT_PENDING = RESULT_ERROR + 8;
final RequiredInputParcel mRequiredInput;
+ // in case operation needs to add to/changes the cryptoInputParcel sent to it
+ public final CryptoInputParcel mCryptoInputParcel;
public InputPendingResult(int result, OperationLog log) {
super(result, log);
mRequiredInput = null;
+ mCryptoInputParcel = null;
}
- public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput) {
+ public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
super(RESULT_PENDING, log);
mRequiredInput = requiredInput;
+ mCryptoInputParcel = cryptoInputParcel;
}
public InputPendingResult(Parcel source) {
super(source);
mRequiredInput = source.readParcelable(getClass().getClassLoader());
+ mCryptoInputParcel = source.readParcelable(getClass().getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(mRequiredInput, 0);
+ dest.writeParcelable(mCryptoInputParcel, 0);
}
public boolean isPending() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java
index 420cbbf01..84648d32c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java
@@ -24,7 +24,10 @@ import android.os.Parcelable;
import com.textuality.keybase.lib.KeybaseException;
import com.textuality.keybase.lib.prover.Prover;
-public class KeybaseVerificationResult extends OperationResult implements Parcelable {
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+
+public class KeybaseVerificationResult extends InputPendingResult {
public final String mProofUrl;
public final String mPresenceUrl;
public final String mPresenceLabel;
@@ -44,6 +47,14 @@ public class KeybaseVerificationResult extends OperationResult implements Parcel
mPresenceLabel = prover.getPresenceLabel();
}
+ public KeybaseVerificationResult(OperationLog log, RequiredInputParcel requiredInputParcel,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInputParcel, cryptoInputParcel);
+ mProofUrl = null;
+ mPresenceUrl = null;
+ mPresenceLabel = null;
+ }
+
protected KeybaseVerificationResult(Parcel in) {
super(in);
mProofUrl = in.readString();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
index f0561bef2..04013e9ed 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
@@ -482,6 +482,7 @@ public abstract class OperationResult implements Parcelable {
// secret key modify
MSG_MF (LogLevel.START, R.string.msg_mr),
MSG_MF_DIVERT (LogLevel.DEBUG, R.string.msg_mf_divert),
+ MSG_MF_ERROR_DIVERT_NEWSUB (LogLevel.ERROR, R.string.msg_mf_error_divert_newsub),
MSG_MF_ERROR_DIVERT_SERIAL (LogLevel.ERROR, R.string.msg_mf_error_divert_serial),
MSG_MF_ERROR_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode),
MSG_MF_ERROR_FINGERPRINT (LogLevel.ERROR, R.string.msg_mf_error_fingerprint),
@@ -499,6 +500,7 @@ public abstract class OperationResult implements Parcelable {
MSG_MF_ERROR_RESTRICTED(LogLevel.ERROR, R.string.msg_mf_error_restricted),
MSG_MF_ERROR_REVOKED_PRIMARY (LogLevel.ERROR, R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_SIG (LogLevel.ERROR, R.string.msg_mf_error_sig),
+ MSG_MF_ERROR_SUB_STRIPPED(LogLevel.ERROR, R.string.msg_mf_error_sub_stripped),
MSG_MF_ERROR_SUBKEY_MISSING(LogLevel.ERROR, R.string.msg_mf_error_subkey_missing),
MSG_MF_ERROR_CONFLICTING_NFC_COMMANDS(LogLevel.ERROR, R.string.msg_mf_error_conflicting_nfc_commands),
MSG_MF_ERROR_DUPLICATE_KEYTOCARD_FOR_SLOT(LogLevel.ERROR, R.string.msg_mf_error_duplicate_keytocard_for_slot),
@@ -510,6 +512,8 @@ public abstract class OperationResult implements Parcelable {
MSG_MF_NOTATION_PIN (LogLevel.DEBUG, R.string.msg_mf_notation_pin),
MSG_MF_NOTATION_EMPTY (LogLevel.DEBUG, R.string.msg_mf_notation_empty),
MSG_MF_PASSPHRASE (LogLevel.INFO, R.string.msg_mf_passphrase),
+ MSG_MF_PIN (LogLevel.INFO, R.string.msg_mf_pin),
+ MSG_MF_ADMIN_PIN (LogLevel.INFO, R.string.msg_mf_admin_pin),
MSG_MF_PASSPHRASE_KEY (LogLevel.DEBUG, R.string.msg_mf_passphrase_key),
MSG_MF_PASSPHRASE_EMPTY_RETRY (LogLevel.DEBUG, R.string.msg_mf_passphrase_empty_retry),
MSG_MF_PASSPHRASE_FAIL (LogLevel.WARN, R.string.msg_mf_passphrase_fail),
@@ -567,6 +571,8 @@ public abstract class OperationResult implements Parcelable {
MSG_ED_CACHING_NEW (LogLevel.DEBUG, R.string.msg_ed_caching_new),
MSG_ED_ERROR_NO_PARCEL (LogLevel.ERROR, R.string.msg_ed_error_no_parcel),
MSG_ED_ERROR_KEY_NOT_FOUND (LogLevel.ERROR, R.string.msg_ed_error_key_not_found),
+ MSG_ED_ERROR_EXTRACTING_PUBLIC_UPLOAD (LogLevel.ERROR,
+ R.string.msg_ed_error_extract_public_upload),
MSG_ED_FETCHING (LogLevel.DEBUG, R.string.msg_ed_fetching),
MSG_ED_SUCCESS (LogLevel.OK, R.string.msg_ed_success),
@@ -601,12 +607,14 @@ public abstract class OperationResult implements Parcelable {
MSG_DC_CLEAR_SIGNATURE_OK (LogLevel.OK, R.string.msg_dc_clear_signature_ok),
MSG_DC_CLEAR_SIGNATURE (LogLevel.DEBUG, R.string.msg_dc_clear_signature),
MSG_DC_ERROR_BAD_PASSPHRASE (LogLevel.ERROR, R.string.msg_dc_error_bad_passphrase),
+ MSG_DC_ERROR_SYM_PASSPHRASE (LogLevel.ERROR, R.string.msg_dc_error_sym_passphrase),
MSG_DC_ERROR_CORRUPT_DATA (LogLevel.ERROR, R.string.msg_dc_error_corrupt_data),
MSG_DC_ERROR_EXTRACT_KEY (LogLevel.ERROR, R.string.msg_dc_error_extract_key),
MSG_DC_ERROR_INTEGRITY_CHECK (LogLevel.ERROR, R.string.msg_dc_error_integrity_check),
MSG_DC_ERROR_INTEGRITY_MISSING (LogLevel.ERROR, R.string.msg_dc_error_integrity_missing),
MSG_DC_ERROR_INVALID_DATA (LogLevel.ERROR, R.string.msg_dc_error_invalid_data),
MSG_DC_ERROR_IO (LogLevel.ERROR, R.string.msg_dc_error_io),
+ MSG_DC_ERROR_INPUT (LogLevel.ERROR, R.string.msg_dc_error_input),
MSG_DC_ERROR_NO_DATA (LogLevel.ERROR, R.string.msg_dc_error_no_data),
MSG_DC_ERROR_NO_KEY (LogLevel.ERROR, R.string.msg_dc_error_no_key),
MSG_DC_ERROR_PGP_EXCEPTION (LogLevel.ERROR, R.string.msg_dc_error_pgp_exception),
@@ -690,6 +698,7 @@ public abstract class OperationResult implements Parcelable {
MSG_CRT_WARN_NOT_FOUND (LogLevel.WARN, R.string.msg_crt_warn_not_found),
MSG_CRT_WARN_CERT_FAILED (LogLevel.WARN, R.string.msg_crt_warn_cert_failed),
MSG_CRT_WARN_SAVE_FAILED (LogLevel.WARN, R.string.msg_crt_warn_save_failed),
+ MSG_CRT_WARN_UPLOAD_FAILED (LogLevel.WARN, R.string.msg_crt_warn_upload_failed),
MSG_IMPORT (LogLevel.START, R.plurals.msg_import),
@@ -710,6 +719,7 @@ public abstract class OperationResult implements Parcelable {
MSG_IMPORT_SUCCESS (LogLevel.OK, R.string.msg_import_success),
MSG_EXPORT (LogLevel.START, R.plurals.msg_export),
+ MSG_EXPORT_UPLOAD_PUBLIC (LogLevel.START, R.string.msg_export_upload_public),
MSG_EXPORT_PUBLIC (LogLevel.DEBUG, R.string.msg_export_public),
MSG_EXPORT_SECRET (LogLevel.DEBUG, R.string.msg_export_secret),
MSG_EXPORT_ALL (LogLevel.START, R.string.msg_export_all),
@@ -721,7 +731,9 @@ public abstract class OperationResult implements Parcelable {
MSG_EXPORT_ERROR_DB (LogLevel.ERROR, R.string.msg_export_error_db),
MSG_EXPORT_ERROR_IO (LogLevel.ERROR, R.string.msg_export_error_io),
MSG_EXPORT_ERROR_KEY (LogLevel.ERROR, R.string.msg_export_error_key),
+ MSG_EXPORT_ERROR_UPLOAD (LogLevel.ERROR, R.string.msg_export_error_upload),
MSG_EXPORT_SUCCESS (LogLevel.OK, R.string.msg_export_success),
+ MSG_EXPORT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_export_upload_success),
MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success),
@@ -742,7 +754,7 @@ public abstract class OperationResult implements Parcelable {
MSG_GET_QUERY_FAILED(LogLevel.ERROR, R.string.msg_download_query_failed),
MSG_DEL_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_del_error_empty),
- MSG_DEL_ERROR_MULTI_SECRET (LogLevel.DEBUG, R.string.msg_del_error_multi_secret),
+ MSG_DEL_ERROR_MULTI_SECRET (LogLevel.ERROR, R.string.msg_del_error_multi_secret),
MSG_DEL (LogLevel.START, R.plurals.msg_del),
MSG_DEL_KEY (LogLevel.DEBUG, R.string.msg_del_key),
MSG_DEL_KEY_FAIL (LogLevel.WARN, R.string.msg_del_key_fail),
@@ -750,6 +762,13 @@ public abstract class OperationResult implements Parcelable {
MSG_DEL_OK (LogLevel.OK, R.plurals.msg_del_ok),
MSG_DEL_FAIL (LogLevel.WARN, R.plurals.msg_del_fail),
+ MSG_REVOKE_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_revoke_error_empty),
+ MSG_REVOKE_ERROR_MULTI_SECRET (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret),
+ MSG_REVOKE_ERROR_NOT_FOUND (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret),
+ MSG_REVOKE (LogLevel.DEBUG, R.string.msg_revoke_key),
+ MSG_REVOKE_KEY_FAIL (LogLevel.ERROR, R.string.msg_revoke_key_fail),
+ MSG_REVOKE_OK (LogLevel.OK, R.string.msg_revoke_ok),
+
// keybase verification
MSG_KEYBASE_VERIFICATION(LogLevel.START, R.string.msg_keybase_verification),
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java
index 38edbf6ee..30307ba46 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java
@@ -22,6 +22,7 @@ import android.os.Parcel;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@@ -37,8 +38,9 @@ public class PgpEditKeyResult extends InputPendingResult {
mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
}
- public PgpEditKeyResult(OperationLog log, RequiredInputParcel requiredInput) {
- super(log, requiredInput);
+ public PgpEditKeyResult(OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
mRingMasterKeyId = Constants.key.none;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java
index acb265462..2b33b8ace 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java
@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@@ -38,8 +39,9 @@ public class PgpSignEncryptResult extends InputPendingResult {
super(result, log);
}
- public PgpSignEncryptResult(OperationLog log, RequiredInputParcel requiredInput) {
- super(log, requiredInput);
+ public PgpSignEncryptResult(OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
}
public PgpSignEncryptResult(Parcel source) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java
new file mode 100644
index 000000000..b737f6e50
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@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
+ * 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.operations.results;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.Nullable;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
+import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+
+public class RevokeResult extends InputPendingResult {
+
+ public final long mMasterKeyId;
+
+ public RevokeResult(int result, OperationLog log, long masterKeyId) {
+ super(result, log);
+ mMasterKeyId = masterKeyId;
+ }
+
+ /**
+ * used when more input is required
+ *
+ * @param log operation log upto point of required input, if any
+ * @param requiredInput represents input required
+ */
+ @SuppressWarnings("unused") // standard pattern across all results, we might need it later
+ public RevokeResult(@Nullable OperationLog log, RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
+ // we won't use these values
+ mMasterKeyId = -1;
+ }
+
+ /** Construct from a parcel - trivial because we have no extra data. */
+ public RevokeResult(Parcel source) {
+ super(source);
+ mMasterKeyId = source.readLong();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeLong(mMasterKeyId);
+ }
+
+ public static final Parcelable.Creator<RevokeResult> CREATOR = new Parcelable.Creator<RevokeResult>() {
+ @Override
+ public RevokeResult createFromParcel(Parcel in) {
+ return new RevokeResult(in);
+ }
+
+ @Override
+ public RevokeResult[] newArray(int size) {
+ return new RevokeResult[size];
+ }
+ };
+
+ @Override
+ public Notify.Showable createNotify(final Activity activity) {
+
+ int resultType = getResult();
+
+ String str;
+ int duration;
+ Notify.Style style;
+
+ // Not an overall failure
+ if ((resultType & OperationResult.RESULT_ERROR) == 0) {
+
+ duration = Notify.LENGTH_LONG;
+
+ // New and updated keys
+ if (resultType == OperationResult.RESULT_OK) {
+ style = Notify.Style.OK;
+ str = activity.getString(R.string.revoke_ok);
+ } else {
+ duration = 0;
+ style = Notify.Style.ERROR;
+ str = "internal error";
+ }
+
+ } else {
+ duration = 0;
+ style = Notify.Style.ERROR;
+ str = activity.getString(R.string.revoke_fail);
+ }
+
+ return Notify.create(activity, str, duration, style, new Notify.ActionListener() {
+ @Override
+ public void onAction() {
+ Intent intent = new Intent(
+ activity, LogDisplayActivity.class);
+ intent.putExtra(LogDisplayFragment.EXTRA_RESULT, RevokeResult.this);
+ activity.startActivity(intent);
+ }
+ }, R.string.snackbar_details);
+
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
index b05921b0d..0e0c5d598 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
@@ -19,18 +19,20 @@ package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel;
-import java.util.ArrayList;
-
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import java.util.ArrayList;
public class SignEncryptResult extends InputPendingResult {
ArrayList<PgpSignEncryptResult> mResults;
byte[] mResultBytes;
- public SignEncryptResult(OperationLog log, RequiredInputParcel requiredInput, ArrayList<PgpSignEncryptResult> results) {
- super(log, requiredInput);
+ public SignEncryptResult(OperationLog log, RequiredInputParcel requiredInput,
+ ArrayList<PgpSignEncryptResult> results,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInput, cryptoInputParcel);
mResults = results;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
index 432ba23e9..770e8de91 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
@@ -27,6 +27,9 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
/** A generic wrapped PGPKeyRing object.
*
@@ -91,6 +94,16 @@ public abstract class CanonicalizedKeyRing extends KeyRing {
return getRing().getPublicKey().isEncryptionKey();
}
+ public Set<Long> getEncryptIds() {
+ HashSet<Long> result = new HashSet<>();
+ for(CanonicalizedPublicKey key : publicKeyIterator()) {
+ if (key.canEncrypt() && key.isValid()) {
+ result.add(key.getKeyId());
+ }
+ }
+ return result;
+ }
+
public long getEncryptId() throws PgpKeyNotFoundException {
for(CanonicalizedPublicKey key : publicKeyIterator()) {
if (key.canEncrypt() && key.isValid()) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
index 676491164..be5f21f23 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
@@ -62,19 +62,6 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {
return mRing;
}
- /** Getter that returns the subkey that should be used for signing. */
- CanonicalizedPublicKey getEncryptionSubKey() throws PgpKeyNotFoundException {
- PGPPublicKey key = getRing().getPublicKey(getEncryptId());
- if(key != null) {
- CanonicalizedPublicKey cKey = new CanonicalizedPublicKey(this, key);
- if(!cKey.canEncrypt()) {
- throw new PgpKeyNotFoundException("key error");
- }
- return cKey;
- }
- throw new PgpKeyNotFoundException("no encryption key available");
- }
-
public IterableIterator<CanonicalizedPublicKey> publicKeyIterator() {
@SuppressWarnings("unchecked")
final Iterator<PGPPublicKey> it = getRing().getPublicKeys();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index a6d260d22..e264b4678 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -19,12 +19,14 @@
package org.sufficientlysecure.keychain.pgp;
import android.content.Context;
+import android.support.annotation.NonNull;
import android.webkit.MimeTypeMap;
import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.openpgp.PGPCompressedData;
+import org.spongycastle.openpgp.PGPDataValidationException;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPEncryptedDataList;
import org.spongycastle.openpgp.PGPException;
@@ -44,7 +46,9 @@ import org.spongycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
+import org.spongycastle.util.encoders.DecoderException;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Constants.key;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.BaseOperation;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
@@ -80,9 +84,8 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
super(context, providerHelper, progressable);
}
- /**
- * Decrypts and/or verifies data based on parameters of class
- */
+ /** Decrypts and/or verifies data based on parameters of PgpDecryptVerifyInputParcel. */
+ @NonNull
public DecryptVerifyResult execute(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput) {
InputData inputData;
OutputStream outputStream;
@@ -96,8 +99,10 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
long inputSize = FileHelper.getFileSize(mContext, input.getInputUri(), 0);
inputData = new InputData(inputStream, inputSize);
} catch (FileNotFoundException e) {
- e.printStackTrace();
- return null;
+ Log.e(Constants.TAG, "Input URI could not be opened: " + input.getInputUri(), e);
+ OperationLog log = new OperationLog();
+ log.add(LogType.MSG_DC_ERROR_INPUT, 1);
+ return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
}
@@ -107,8 +112,10 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
try {
outputStream = mContext.getContentResolver().openOutputStream(input.getOutputUri());
} catch (FileNotFoundException e) {
- e.printStackTrace();
- return null;
+ Log.e(Constants.TAG, "Output URI could not be opened: " + input.getOutputUri(), e);
+ OperationLog log = new OperationLog();
+ log.add(LogType.MSG_DC_ERROR_IO, 1);
+ return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
}
@@ -122,11 +129,13 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
}
+ @NonNull
public DecryptVerifyResult execute(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
InputData inputData, OutputStream outputStream) {
return executeInternal(input, cryptoInput, inputData, outputStream);
}
+ @NonNull
private DecryptVerifyResult executeInternal(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
InputData inputData, OutputStream outputStream) {
try {
@@ -161,6 +170,13 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
OperationLog log = new OperationLog();
log.add(LogType.MSG_DC_ERROR_PGP_EXCEPTION, 1);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
+ } catch (DecoderException | ArrayIndexOutOfBoundsException e) {
+ // these can happen if assumptions in JcaPGPObjectFactory.nextObject() aren't
+ // fulfilled, so we need to catch them here to handle this gracefully
+ Log.d(Constants.TAG, "data error", e);
+ OperationLog log = new OperationLog();
+ log.add(LogType.MSG_DC_ERROR_IO, 1);
+ return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
} catch (IOException e) {
Log.d(Constants.TAG, "IOException", e);
OperationLog log = new OperationLog();
@@ -169,9 +185,8 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
}
}
- /**
- * Verify Keybase.io style signed literal data
- */
+ /**Verify signed plaintext data (PGP/INLINE). */
+ @NonNull
private DecryptVerifyResult verifySignedLiteralData(
PgpDecryptVerifyInputParcel input, InputStream in, OutputStream out, int indent)
throws IOException, PGPException {
@@ -301,9 +316,8 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
}
- /**
- * Decrypt and/or verifies binary or ascii armored pgp
- */
+ /** Decrypt and/or verify binary or ascii armored pgp data. */
+ @NonNull
private DecryptVerifyResult decryptVerify(
PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
InputStream in, OutputStream out, int indent) throws IOException, PGPException {
@@ -445,7 +459,8 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
return new DecryptVerifyResult(log,
RequiredInputParcel.createRequiredDecryptPassphrase(
- secretKeyRing.getMasterKeyId(), secretEncryptionKey.getKeyId()));
+ secretKeyRing.getMasterKeyId(), secretEncryptionKey.getKeyId()),
+ cryptoInput);
}
}
@@ -473,12 +488,24 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
// if no passphrase is given, return here
// indicating that a passphrase is missing!
if (!cryptoInput.hasPassphrase()) {
- log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
- return new DecryptVerifyResult(log,
- RequiredInputParcel.createRequiredSymmetricPassphrase());
- }
- passphrase = cryptoInput.getPassphrase();
+ try {
+ passphrase = getCachedPassphrase(key.symmetric);
+ log.add(LogType.MSG_DC_PASS_CACHED, indent + 1);
+ } catch (PassphraseCacheInterface.NoSecretKeyException e) {
+ // nvm
+ }
+
+ if (passphrase == null) {
+ log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
+ return new DecryptVerifyResult(log,
+ RequiredInputParcel.createRequiredSymmetricPassphrase(),
+ cryptoInput);
+ }
+
+ } else {
+ passphrase = cryptoInput.getPassphrase();
+ }
// break out of while, only decrypt the first packet
break;
@@ -514,7 +541,14 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
passphrase.getCharArray());
- clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
+ try {
+ clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
+ } catch (PGPDataValidationException e) {
+ log.add(LogType.MSG_DC_ERROR_SYM_PASSPHRASE, indent +1);
+ return new DecryptVerifyResult(log,
+ RequiredInputParcel.createRequiredSymmetricPassphrase(), cryptoInput);
+ }
+
encryptedData = encryptedDataSymmetric;
symmetricEncryptionAlgo = encryptedDataSymmetric.getSymmetricAlgorithm(decryptorFactory);
@@ -548,7 +582,8 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
return new DecryptVerifyResult(log, RequiredInputParcel.createNfcDecryptOperation(
secretEncryptionKey.getRing().getMasterKeyId(),
secretEncryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0]
- ));
+ ),
+ cryptoInput);
}
@@ -843,6 +878,7 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
* The method is heavily based on
* pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
*/
+ @NonNull
private DecryptVerifyResult verifyCleartextSignature(
ArmoredInputStream aIn, OutputStream outputStream, int indent) throws IOException, PGPException {
@@ -950,6 +986,7 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
return result;
}
+ @NonNull
private DecryptVerifyResult verifyDetachedSignature(
PgpDecryptVerifyInputParcel input, InputData inputData, OutputStream out, int indent)
throws IOException, PGPException {
@@ -1042,7 +1079,9 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
return result;
}
- private PGPSignature processPGPSignatureList(PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder) throws PGPException {
+ private PGPSignature processPGPSignatureList(
+ PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder)
+ throws PGPException {
CanonicalizedPublicKeyRing signingRing = null;
CanonicalizedPublicKey signingKey = null;
int signatureIndex = -1;
@@ -1178,12 +1217,6 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
private static byte[] getLineSeparator() {
String nl = System.getProperty("line.separator");
- byte[] nlBytes = new byte[nl.length()];
-
- for (int i = 0; i != nlBytes.length; i++) {
- nlBytes[i] = (byte) nl.charAt(i);
- }
-
- return nlBytes;
+ return nl.getBytes();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index a018815f3..c82cbce8f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -22,6 +22,7 @@ import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.S2K;
import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
+import org.spongycastle.bcpg.sig.RevocationReasonTags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyFlags;
@@ -469,7 +470,7 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_REQUIRE_PASSPHRASE, indent);
return new PgpEditKeyResult(log, RequiredInputParcel.createRequiredSignPassphrase(
masterSecretKey.getKeyID(), masterSecretKey.getKeyID(),
- cryptoInput.getSignatureTime()));
+ cryptoInput.getSignatureTime()), cryptoInput);
}
// read masterKeyFlags, and use the same as before.
@@ -897,18 +898,35 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.removeCertification(pKey, sig);
}
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- cryptoInput.getPassphrase().getCharArray());
- PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
- PGPSignature sig = generateSubkeyBindingSignature(
- getSignatureGenerator(masterSecretKey, cryptoInput),
- cryptoInput.getSignatureTime(),
- masterPublicKey, masterPrivateKey, subPrivateKey, pKey, flags, expiry);
+ PGPPrivateKey subPrivateKey;
+ if (!isDivertToCard(sKey)) {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ cryptoInput.getPassphrase().getCharArray());
+ subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
+ // super special case: subkey is allowed to sign, but isn't available
+ if (subPrivateKey == null) {
+ log.add(LogType.MSG_MF_ERROR_SUB_STRIPPED,
+ indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
+ return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
+ }
+ } else {
+ subPrivateKey = null;
+ }
+ try {
+ PGPSignature sig = generateSubkeyBindingSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(), masterPublicKey, masterPrivateKey,
+ getSignatureGenerator(sKey, cryptoInput), subPrivateKey,
+ pKey, flags, expiry);
+
+ // generate and add new signature
+ pKey = PGPPublicKey.addCertification(pKey, sig);
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
- // generate and add new signature
- pKey = PGPPublicKey.addCertification(pKey, sig);
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
subProgressPop();
@@ -959,6 +977,11 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_SUBKEY_NEW, indent,
KeyFormattingUtils.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve) );
+ if (isDivertToCard(masterSecretKey)) {
+ log.add(LogType.MSG_MF_ERROR_DIVERT_NEWSUB, indent +1);
+ return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
+ }
+
if (add.mExpiry == null) {
log.add(LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
@@ -987,7 +1010,8 @@ public class PgpKeyOperation {
PGPSignature cert = generateSubkeyBindingSignature(
getSignatureGenerator(masterSecretKey, cryptoInput),
cryptoInput.getSignatureTime(),
- masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
+ masterPublicKey, masterPrivateKey,
+ getSignatureGenerator(pKey, cryptoInput, false), keyPair.getPrivateKey(), pKey,
add.mFlags, add.mExpiry);
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
} catch (NfcInteractionNeeded e) {
@@ -1039,6 +1063,26 @@ public class PgpKeyOperation {
indent -= 1;
}
+ // 7. if requested, change PIN and/or Admin PIN on card
+ if (saveParcel.mCardPin != null) {
+ progress(R.string.progress_modify_pin, 90);
+ log.add(LogType.MSG_MF_PIN, indent);
+ indent += 1;
+
+ nfcKeyToCardOps.setPin(saveParcel.mCardPin);
+
+ indent -= 1;
+ }
+ if (saveParcel.mCardAdminPin != null) {
+ progress(R.string.progress_modify_admin_pin, 90);
+ log.add(LogType.MSG_MF_ADMIN_PIN, indent);
+ indent += 1;
+
+ nfcKeyToCardOps.setAdminPin(saveParcel.mCardAdminPin);
+
+ indent -= 1;
+ }
+
} catch (IOException e) {
Log.e(Constants.TAG, "encountered IOException while modifying key", e);
log.add(LogType.MSG_MF_ERROR_ENCODE, indent+1);
@@ -1062,12 +1106,12 @@ public class PgpKeyOperation {
if (!nfcSignOps.isEmpty()) {
log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent);
- return new PgpEditKeyResult(log, nfcSignOps.build());
+ return new PgpEditKeyResult(log, nfcSignOps.build(), cryptoInput);
}
if (!nfcKeyToCardOps.isEmpty()) {
log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent);
- return new PgpEditKeyResult(log, nfcKeyToCardOps.build());
+ return new PgpEditKeyResult(log, nfcKeyToCardOps.build(), cryptoInput);
}
log.add(LogType.MSG_MF_SUCCESS, indent);
@@ -1382,22 +1426,27 @@ public class PgpKeyOperation {
static PGPSignatureGenerator getSignatureGenerator(
PGPSecretKey secretKey, CryptoInputParcel cryptoInput) {
- PGPContentSignerBuilder builder;
-
S2K s2k = secretKey.getS2K();
- if (s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
- && s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD) {
+ boolean isDivertToCard = s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
+ && s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD;
+
+ return getSignatureGenerator(secretKey.getPublicKey(), cryptoInput, isDivertToCard);
+ }
+
+ static PGPSignatureGenerator getSignatureGenerator(
+ PGPPublicKey pKey, CryptoInputParcel cryptoInput, boolean divertToCard) {
+
+ PGPContentSignerBuilder builder;
+ if (divertToCard) {
// use synchronous "NFC based" SignerBuilder
builder = new NfcSyncPGPContentSignerBuilder(
- secretKey.getPublicKey().getAlgorithm(),
- PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
- secretKey.getKeyID(), cryptoInput.getCryptoData())
+ pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
+ pKey.getKeyID(), cryptoInput.getCryptoData())
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
} else {
// content signer based on signing key algorithm and chosen hash algorithm
builder = new JcaPGPContentSignerBuilder(
- secretKey.getPublicKey().getAlgorithm(),
- PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
+ pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
}
@@ -1477,6 +1526,9 @@ public class PgpKeyOperation {
throws IOException, PGPException, SignatureException {
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
+ // we use the tag NO_REASON since gnupg does not care about the tag while verifying
+ // signatures with a revoked key, the warning is the same
+ subHashedPacketsGen.setRevocationReason(true, RevocationReasonTags.NO_REASON, "");
subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
@@ -1489,6 +1541,9 @@ public class PgpKeyOperation {
throws IOException, PGPException, SignatureException {
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
+ // we use the tag NO_REASON since gnupg does not care about the tag while verifying
+ // signatures with a revoked key, the warning is the same
+ subHashedPacketsGen.setRevocationReason(true, RevocationReasonTags.NO_REASON, "");
subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
// Generate key revocation or subkey revocation, depending on master/subkey-ness
@@ -1504,7 +1559,8 @@ public class PgpKeyOperation {
static PGPSignature generateSubkeyBindingSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
- PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
+ PGPSignatureGenerator subSigGen, PGPPrivateKey subPrivateKey, PGPPublicKey pKey,
+ int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -1514,10 +1570,6 @@ public class PgpKeyOperation {
// cross-certify signing keys
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator subSigGen = new PGPSignatureGenerator(signerBuilder);
subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
index 89bdf1c89..8fb41a909 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
@@ -20,6 +20,8 @@
package org.sufficientlysecure.keychain.pgp;
import android.content.Context;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream;
@@ -36,11 +38,11 @@ import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.BaseOperation;
+import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -63,6 +65,7 @@ import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -99,6 +102,13 @@ public class PgpSignEncryptOperation extends BaseOperation {
super(context, providerHelper, progressable);
}
+ @NonNull
+ @Override
+ // TODO this is horrible, refactor ASAP!!
+ public OperationResult execute(Parcelable input, CryptoInputParcel cryptoInput) {
+ return null;
+ }
+
/**
* Signs and/or encrypts data based on parameters of class
*/
@@ -189,7 +199,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1);
return new PgpSignEncryptResult(log, RequiredInputParcel.createRequiredSignPassphrase(
signingKeyRing.getMasterKeyId(), signingKey.getKeyId(),
- cryptoInput.getSignatureTime()));
+ cryptoInput.getSignatureTime()), cryptoInput);
}
if (!signingKey.unlock(localPassphrase)) {
log.add(LogType.MSG_PSE_ERROR_BAD_PASSPHRASE, indent);
@@ -263,15 +273,19 @@ public class PgpSignEncryptOperation extends BaseOperation {
try {
CanonicalizedPublicKeyRing keyRing = mProviderHelper.getCanonicalizedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(id));
- CanonicalizedPublicKey key = keyRing.getEncryptionSubKey();
- cPk.addMethod(key.getPubKeyEncryptionGenerator(input.isHiddenRecipients()));
- log.add(LogType.MSG_PSE_KEY_OK, indent + 1,
- KeyFormattingUtils.convertKeyIdToHex(id));
- } catch (PgpKeyNotFoundException e) {
- log.add(LogType.MSG_PSE_KEY_WARN, indent + 1,
- KeyFormattingUtils.convertKeyIdToHex(id));
- if (input.isFailOnMissingEncryptionKeyIds()) {
- return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
+ Set<Long> encryptSubKeyIds = keyRing.getEncryptIds();
+ for (Long subKeyId : encryptSubKeyIds) {
+ CanonicalizedPublicKey key = keyRing.getPublicKey(subKeyId);
+ cPk.addMethod(key.getPubKeyEncryptionGenerator(input.isHiddenRecipients()));
+ log.add(LogType.MSG_PSE_KEY_OK, indent + 1,
+ KeyFormattingUtils.convertKeyIdToHex(subKeyId));
+ }
+ if (encryptSubKeyIds.isEmpty()) {
+ log.add(LogType.MSG_PSE_KEY_WARN, indent + 1,
+ KeyFormattingUtils.convertKeyIdToHex(id));
+ if (input.isFailOnMissingEncryptionKeyIds()) {
+ return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
+ }
}
} catch (ProviderHelper.NotFoundException e) {
log.add(LogType.MSG_PSE_KEY_UNKNOWN, indent + 1,
@@ -498,7 +512,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
log.add(LogType.MSG_PSE_PENDING_NFC, indent);
return new PgpSignEncryptResult(log, RequiredInputParcel.createNfcSignOperation(
signingKey.getRing().getMasterKeyId(), signingKey.getKeyId(),
- e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime()));
+ e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime()), cryptoInput);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 7be61d9c8..a7baddf8b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -48,6 +48,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -78,7 +79,7 @@ import java.util.TreeSet;
*
*/
@SuppressWarnings("unchecked")
-public class UncachedKeyRing {
+public class UncachedKeyRing implements Serializable {
final PGPKeyRing mRing;
final boolean mIsSecret;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 3346926ec..4d16d44c5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -53,7 +53,7 @@ import java.io.IOException;
*/
public class KeychainDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "openkeychain.db";
- private static final int DATABASE_VERSION = 10;
+ private static final int DATABASE_VERSION = 11;
static Boolean apgHack = false;
private Context mContext;
@@ -274,6 +274,14 @@ public class KeychainDatabase extends SQLiteOpenHelper {
db.execSQL(CREATE_CERTS);
case 10:
// do nothing here, just consolidate
+ case 11:
+ // fix problems in database, see #1402 for details
+ // https://github.com/open-keychain/open-keychain/issues/1402
+ db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3");
+ if (oldVersion == 10) {
+ // no consolidate if we are updating from 10, we're just here for the api_accounts fix
+ return;
+ }
}
@@ -297,10 +305,11 @@ public class KeychainDatabase extends SQLiteOpenHelper {
// It's the Java way =(
String[] dbs = context.databaseList();
for (String db : dbs) {
- if (db.equals("apg.db")) {
+ if ("apg.db".equals(db)) {
hasApgDb = true;
- } else if (db.equals("apg_old.db")) {
+ } else if ("apg_old.db".equals(db)) {
Log.d(Constants.TAG, "Found apg_old.db, delete it!");
+ // noinspection ResultOfMethodCallIgnored - if it doesn't happen, it doesn't happen.
context.getDatabasePath("apg_old.db").delete();
}
}
@@ -384,7 +393,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
}
}
- // delete old database
+ // noinspection ResultOfMethodCallIgnored - not much we can do if this doesn't work
context.getDatabasePath("apg.db").delete();
}
@@ -416,6 +425,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
} else {
in = context.getDatabasePath(DATABASE_NAME);
out = context.getDatabasePath("debug_backup.db");
+ // noinspection ResultOfMethodCallIgnored - this is a pure debug feature, anyways
out.createNewFile();
}
if (!in.canRead()) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 590c58f97..ed17de4ab 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -26,6 +26,7 @@ import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
import android.support.v4.util.LongSparseArray;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
@@ -725,7 +726,7 @@ public class ProviderHelper {
LongSparseArray<WrappedSignature> trustedCerts = new LongSparseArray<>();
@Override
- public int compareTo(UserPacketItem o) {
+ public int compareTo(@NonNull UserPacketItem o) {
// revoked keys always come last!
//noinspection DoubleNegation
if ((selfRevocation != null) != (o.selfRevocation != null)) {
@@ -906,7 +907,8 @@ public class ProviderHelper {
// If there is a secret key, merge new data (if any) and save the key for later
CanonicalizedSecretKeyRing canSecretRing;
try {
- UncachedKeyRing secretRing = getCanonicalizedSecretKeyRing(publicRing.getMasterKeyId()).getUncachedKeyRing();
+ UncachedKeyRing secretRing = getCanonicalizedSecretKeyRing(publicRing.getMasterKeyId())
+ .getUncachedKeyRing();
// Merge data from new public ring into secret one
log(LogType.MSG_IP_MERGE_SECRET);
@@ -1031,7 +1033,8 @@ public class ProviderHelper {
publicRing = secretRing.extractPublicKeyRing();
}
- CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
+ CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog,
+ mIndent);
if (canPublicRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
}
@@ -1057,6 +1060,7 @@ public class ProviderHelper {
}
+ @NonNull
public ConsolidateResult consolidateDatabaseStep1(Progressable progress) {
OperationLog log = new OperationLog();
@@ -1082,7 +1086,7 @@ public class ProviderHelper {
indent += 1;
final Cursor cursor = mContentResolver.query(KeyRingData.buildSecretKeyRingUri(),
- new String[]{ KeyRingData.KEY_RING_DATA }, null, null, null);
+ new String[]{KeyRingData.KEY_RING_DATA}, null, null, null);
if (cursor == null) {
log.add(LogType.MSG_CON_ERROR_DB, indent);
@@ -1124,6 +1128,7 @@ public class ProviderHelper {
}
});
+ cursor.close();
} catch (IOException e) {
Log.e(Constants.TAG, "error saving secret", e);
@@ -1143,7 +1148,7 @@ public class ProviderHelper {
final Cursor cursor = mContentResolver.query(
KeyRingData.buildPublicKeyRingUri(),
- new String[]{ KeyRingData.KEY_RING_DATA }, null, null, null);
+ new String[]{KeyRingData.KEY_RING_DATA}, null, null, null);
if (cursor == null) {
log.add(LogType.MSG_CON_ERROR_DB, indent);
@@ -1185,6 +1190,7 @@ public class ProviderHelper {
}
});
+ cursor.close();
} catch (IOException e) {
Log.e(Constants.TAG, "error saving public", e);
@@ -1200,12 +1206,14 @@ public class ProviderHelper {
return consolidateDatabaseStep2(log, indent, progress, false);
}
+ @NonNull
public ConsolidateResult consolidateDatabaseStep2(Progressable progress) {
return consolidateDatabaseStep2(new OperationLog(), 0, progress, true);
}
private static boolean mConsolidateCritical = false;
+ @NonNull
private ConsolidateResult consolidateDatabaseStep2(
OperationLog log, int indent, Progressable progress, boolean recovery) {
@@ -1250,7 +1258,7 @@ public class ProviderHelper {
ImportKeyResult result = new ImportOperation(mContext, this,
new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport))
- .serialKeyRingImport(itSecrets, numSecrets, null);
+ .serialKeyRingImport(itSecrets, numSecrets, null, null);
log.add(result, indent);
} else {
log.add(LogType.MSG_CON_REIMPORT_SECRET_SKIP, indent);
@@ -1278,7 +1286,7 @@ public class ProviderHelper {
ImportKeyResult result = new ImportOperation(mContext, this,
new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport))
- .serialKeyRingImport(itPublics, numPublics, null);
+ .serialKeyRingImport(itPublics, numPublics, null, null);
log.add(result, indent);
} else {
log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent);
@@ -1414,7 +1422,7 @@ public class ProviderHelper {
private ContentValues contentValueForApiApps(AppSettings appSettings) {
ContentValues values = new ContentValues();
values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName());
- values.put(ApiApps.PACKAGE_CERTIFICATE, appSettings.getPackageSignature());
+ values.put(ApiApps.PACKAGE_CERTIFICATE, appSettings.getPackageCertificate());
return values;
}
@@ -1460,7 +1468,7 @@ public class ProviderHelper {
settings = new AppSettings();
settings.setPackageName(cursor.getString(
cursor.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME)));
- settings.setPackageSignature(cursor.getBlob(
+ settings.setPackageCertificate(cursor.getBlob(
cursor.getColumnIndex(KeychainContract.ApiApps.PACKAGE_CERTIFICATE)));
}
} finally {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java
index a3f9f84c9..498601769 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java
@@ -19,7 +19,7 @@ package org.sufficientlysecure.keychain.remote;
public class AppSettings {
private String mPackageName;
- private byte[] mPackageSignature;
+ private byte[] mPackageCertificate;
public AppSettings() {
@@ -28,7 +28,7 @@ public class AppSettings {
public AppSettings(String packageName, byte[] packageSignature) {
super();
this.mPackageName = packageName;
- this.mPackageSignature = packageSignature;
+ this.mPackageCertificate = packageSignature;
}
public String getPackageName() {
@@ -39,12 +39,12 @@ public class AppSettings {
this.mPackageName = packageName;
}
- public byte[] getPackageSignature() {
- return mPackageSignature;
+ public byte[] getPackageCertificate() {
+ return mPackageCertificate;
}
- public void setPackageSignature(byte[] packageSignature) {
- this.mPackageSignature = packageSignature;
+ public void setPackageCertificate(byte[] packageCertificate) {
+ this.mPackageCertificate = packageCertificate;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index ac66bd097..2568d68b9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -64,6 +64,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashSet;
public class OpenPgpService extends RemoteService {
@@ -88,8 +89,8 @@ public class OpenPgpService extends RemoteService {
boolean duplicateUserIdsCheck = false;
ArrayList<Long> keyIds = new ArrayList<>();
- ArrayList<String> missingUserIds = new ArrayList<>();
- ArrayList<String> duplicateUserIds = new ArrayList<>();
+ ArrayList<String> missingEmails = new ArrayList<>();
+ ArrayList<String> duplicateEmails = new ArrayList<>();
if (!noUserIdsCheck) {
for (String email : encryptionUserIds) {
// try to find the key for this specific email
@@ -102,13 +103,13 @@ public class OpenPgpService extends RemoteService {
keyIds.add(id);
} else {
missingUserIdsCheck = true;
- missingUserIds.add(email);
+ missingEmails.add(email);
Log.d(Constants.TAG, "user id missing");
}
- // another entry for this email -> too keys with the same email inside user id
+ // another entry for this email -> two keys with the same email inside user id
if (cursor != null && cursor.moveToNext()) {
duplicateUserIdsCheck = true;
- duplicateUserIds.add(email);
+ duplicateEmails.add(email);
// also pre-select
long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
@@ -136,8 +137,8 @@ public class OpenPgpService extends RemoteService {
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
intent.putExtra(RemoteServiceActivity.EXTRA_NO_USER_IDS_CHECK, noUserIdsCheck);
- intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
- intent.putExtra(RemoteServiceActivity.EXTRA_DUPLICATE_USER_IDS, duplicateUserIds);
+ intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_EMAILS, missingEmails);
+ intent.putExtra(RemoteServiceActivity.EXTRA_DUPLICATE_EMAILS, duplicateEmails);
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
@@ -164,7 +165,9 @@ public class OpenPgpService extends RemoteService {
}
private static PendingIntent getRequiredInputPendingIntent(Context context,
- Intent data, RequiredInputParcel requiredInput) {
+ Intent data,
+ RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInput) {
switch (requiredInput.mType) {
case NFC_MOVE_KEY_TO_CARD:
@@ -175,6 +178,7 @@ public class OpenPgpService extends RemoteService {
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(NfcOperationActivity.EXTRA_SERVICE_INTENT, data);
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
+ intent.putExtra(NfcOperationActivity.EXTRA_CRYPTO_INPUT, cryptoInput);
return PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
@@ -185,6 +189,7 @@ public class OpenPgpService extends RemoteService {
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(PassphraseDialogActivity.EXTRA_SERVICE_INTENT, data);
intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
+ intent.putExtra(PassphraseDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInput);
return PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
@@ -279,12 +284,12 @@ public class OpenPgpService extends RemoteService {
CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data);
if (inputParcel == null) {
- inputParcel = new CryptoInputParcel();
+ inputParcel = new CryptoInputParcel(new Date());
}
// override passphrase in input parcel if given by API call
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
- inputParcel = new CryptoInputParcel(inputParcel.getSignatureTime(),
- new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)));
+ inputParcel.mPassphrase =
+ new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE));
}
// execute PGP operation!
@@ -294,7 +299,8 @@ public class OpenPgpService extends RemoteService {
if (pgpResult.isPending()) {
RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel();
- PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput);
+ PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data,
+ requiredInput, pgpResult.mCryptoInputParcel);
// return PendingIntent to be executed by client
Intent result = new Intent();
@@ -434,12 +440,12 @@ public class OpenPgpService extends RemoteService {
CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data);
if (inputParcel == null) {
- inputParcel = new CryptoInputParcel();
+ inputParcel = new CryptoInputParcel(new Date());
}
// override passphrase in input parcel if given by API call
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
- inputParcel = new CryptoInputParcel(inputParcel.getSignatureTime(),
- new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)));
+ inputParcel.mPassphrase =
+ new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE));
}
PgpSignEncryptOperation op = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null);
@@ -449,7 +455,8 @@ public class OpenPgpService extends RemoteService {
if (pgpResult.isPending()) {
RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel();
- PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput);
+ PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data,
+ requiredInput, pgpResult.mCryptoInputParcel);
// return PendingIntent to be executed by client
Intent result = new Intent();
@@ -519,8 +526,8 @@ public class OpenPgpService extends RemoteService {
}
// override passphrase in input parcel if given by API call
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
- cryptoInput = new CryptoInputParcel(cryptoInput.getSignatureTime(),
- new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)));
+ cryptoInput.mPassphrase =
+ new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE));
}
byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE);
@@ -543,7 +550,8 @@ public class OpenPgpService extends RemoteService {
if (pgpResult.isPending()) {
// prepare and return PendingIntent to be executed by client
RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel();
- PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput);
+ PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data,
+ requiredInput, pgpResult.mCryptoInputParcel);
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_INTENT, pIntent);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java
index d25249b14..4eee73e01 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java
@@ -75,7 +75,7 @@ public class AppSettingsActivity extends BaseActivity {
mAppNameView = (TextView) findViewById(R.id.api_app_settings_app_name);
mAppIconView = (ImageView) findViewById(R.id.api_app_settings_app_icon);
mPackageName = (TextView) findViewById(R.id.api_app_settings_package_name);
- mPackageSignature = (TextView) findViewById(R.id.api_app_settings_package_signature);
+ mPackageSignature = (TextView) findViewById(R.id.api_app_settings_package_certificate);
mStartFab = (FloatingActionButton) findViewById(R.id.fab);
mStartFab.setOnClickListener(new View.OnClickListener() {
@@ -148,19 +148,19 @@ public class AppSettingsActivity extends BaseActivity {
}
private void showAdvancedInfo() {
- String signature = null;
- // advanced info: package signature SHA-256
+ String certificate = null;
+ // advanced info: package certificate SHA-256
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
- md.update(mAppSettings.getPackageSignature());
+ md.update(mAppSettings.getPackageCertificate());
byte[] digest = md.digest();
- signature = new String(Hex.encode(digest));
+ certificate = new String(Hex.encode(digest));
} catch (NoSuchAlgorithmException e) {
Log.e(Constants.TAG, "Should not happen!", e);
}
AdvancedAppSettingsDialogFragment dialogFragment =
- AdvancedAppSettingsDialogFragment.newInstance(mAppSettings.getPackageName(), signature);
+ AdvancedAppSettingsDialogFragment.newInstance(mAppSettings.getPackageName(), certificate);
dialogFragment.show(getSupportFragmentManager(), "advancedDialog");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java
index 7beac8973..9160987ab 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java
@@ -47,7 +47,7 @@ public class AppSettingsHeaderFragment extends Fragment {
private TextView mAppNameView;
private ImageView mAppIconView;
private TextView mPackageName;
- private TextView mPackageSignature;
+ private TextView mPackageCertificate;
public AppSettings getAppSettings() {
return mAppSettings;
@@ -67,7 +67,7 @@ public class AppSettingsHeaderFragment extends Fragment {
mAppNameView = (TextView) view.findViewById(R.id.api_app_settings_app_name);
mAppIconView = (ImageView) view.findViewById(R.id.api_app_settings_app_icon);
mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name);
- mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature);
+ mPackageCertificate = (TextView) view.findViewById(R.id.api_app_settings_package_certificate);
return view;
}
@@ -94,11 +94,11 @@ public class AppSettingsHeaderFragment extends Fragment {
// advanced info: package signature SHA-256
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
- md.update(appSettings.getPackageSignature());
+ md.update(appSettings.getPackageCertificate());
byte[] digest = md.digest();
String signature = new String(Hex.encode(digest));
- mPackageSignature.setText(signature);
+ mPackageCertificate.setText(signature);
} catch (NoSuchAlgorithmException e) {
Log.e(Constants.TAG, "Should not happen!", e);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
index 5facde64f..a2e781e8a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
@@ -69,8 +69,8 @@ public class RemoteServiceActivity extends BaseActivity {
public static final String EXTRA_ACC_NAME = "acc_name";
// select pub keys action
public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids";
- public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids";
- public static final String EXTRA_DUPLICATE_USER_IDS = "dublicate_user_ids";
+ public static final String EXTRA_MISSING_EMAILS = "missing_emails";
+ public static final String EXTRA_DUPLICATE_EMAILS = "dublicate_emails";
public static final String EXTRA_NO_USER_IDS_CHECK = "no_user_ids";
// error message
public static final String EXTRA_ERROR_MESSAGE = "error_message";
@@ -222,10 +222,10 @@ public class RemoteServiceActivity extends BaseActivity {
case ACTION_SELECT_PUB_KEYS: {
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true);
- ArrayList<String> missingUserIds = intent
- .getStringArrayListExtra(EXTRA_MISSING_USER_IDS);
- ArrayList<String> dublicateUserIds = intent
- .getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS);
+ ArrayList<String> missingEmails = intent
+ .getStringArrayListExtra(EXTRA_MISSING_EMAILS);
+ ArrayList<String> duplicateEmails = intent
+ .getStringArrayListExtra(EXTRA_DUPLICATE_EMAILS);
SpannableStringBuilder ssb = new SpannableStringBuilder();
final SpannableString textIntro = new SpannableString(
@@ -235,23 +235,23 @@ public class RemoteServiceActivity extends BaseActivity {
textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append(textIntro);
- if (missingUserIds != null && missingUserIds.size() > 0) {
+ if (missingEmails != null && missingEmails.size() > 0) {
ssb.append("\n\n");
ssb.append(getString(R.string.api_select_pub_keys_missing_text));
ssb.append("\n");
- for (String userId : missingUserIds) {
- SpannableString ss = new SpannableString(userId + "\n");
+ for (String emails : missingEmails) {
+ SpannableString ss = new SpannableString(emails + "\n");
ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append(ss);
}
}
- if (dublicateUserIds != null && dublicateUserIds.size() > 0) {
+ if (duplicateEmails != null && duplicateEmails.size() > 0) {
ssb.append("\n\n");
ssb.append(getString(R.string.api_select_pub_keys_dublicates_text));
ssb.append("\n");
- for (String userId : dublicateUserIds) {
- SpannableString ss = new SpannableString(userId + "\n");
+ for (String email : duplicateEmails) {
+ SpannableString ss = new SpannableString(email + "\n");
ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append(ss);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
index a11f81658..e76dcfb49 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
@@ -22,13 +22,10 @@ import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Date;
-import java.util.Map;
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
-import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
/**
@@ -54,6 +51,7 @@ public class CertifyActionsParcel implements Parcelable {
mMasterKeyId = source.readLong();
// just like parcelables, this is meant for ad-hoc IPC only and is NOT portable!
mLevel = CertifyLevel.values()[source.readInt()];
+ keyServerUri = source.readString();
mCertifyActions = (ArrayList<CertifyAction>) source.readSerializable();
}
@@ -66,6 +64,7 @@ public class CertifyActionsParcel implements Parcelable {
public void writeToParcel(Parcel destination, int flags) {
destination.writeLong(mMasterKeyId);
destination.writeInt(mLevel.ordinal());
+ destination.writeString(keyServerUri);
destination.writeSerializable(mCertifyActions);
}
@@ -94,7 +93,7 @@ public class CertifyActionsParcel implements Parcelable {
}
public CertifyAction(long masterKeyId, ArrayList<String> userIds,
- ArrayList<WrappedUserAttribute> attributes) {
+ ArrayList<WrappedUserAttribute> attributes) {
mMasterKeyId = masterKeyId;
mUserIds = userIds;
mUserAttributes = attributes;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java
index 41ff6d02b..18bc3cc9d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java
@@ -83,7 +83,7 @@ public class DummyAccountService extends Service {
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType,
String[] requiredFeatures, Bundle options) throws NetworkErrorException {
response.onResult(new Bundle());
- toaster.toast(R.string.info_no_manual_account_creation);
+ toaster.toast(R.string.account_no_manual_account_creation);
Log.d(Constants.TAG, "DummyAccountService.addAccount");
return null;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java
index ef5b48df3..24c002bbd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java
@@ -23,9 +23,12 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
+
public class ExportKeyringParcel implements Parcelable {
public String mKeyserver;
public Uri mCanonicalizedPublicKeyringUri;
+ public UncachedKeyRing mUncachedKeyRing;
public boolean mExportSecret;
public long mMasterKeyIds[];
@@ -45,6 +48,12 @@ public class ExportKeyringParcel implements Parcelable {
mCanonicalizedPublicKeyringUri = keyringUri;
}
+ public ExportKeyringParcel(String keyserver, UncachedKeyRing uncachedKeyRing) {
+ mExportType = ExportType.UPLOAD_KEYSERVER;
+ mKeyserver = keyserver;
+ mUncachedKeyRing = uncachedKeyRing;
+ }
+
public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, String outputFile) {
mExportType = ExportType.EXPORT_FILE;
mMasterKeyIds = masterKeyIds;
@@ -52,6 +61,7 @@ public class ExportKeyringParcel implements Parcelable {
mOutputFile = outputFile;
}
+ @SuppressWarnings("unused") // TODO: is it used?
public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, Uri outputUri) {
mExportType = ExportType.EXPORT_URI;
mMasterKeyIds = masterKeyIds;
@@ -62,6 +72,7 @@ public class ExportKeyringParcel implements Parcelable {
protected ExportKeyringParcel(Parcel in) {
mKeyserver = in.readString();
mCanonicalizedPublicKeyringUri = (Uri) in.readValue(Uri.class.getClassLoader());
+ mUncachedKeyRing = (UncachedKeyRing) in.readValue(UncachedKeyRing.class.getClassLoader());
mExportSecret = in.readByte() != 0x00;
mOutputFile = in.readString();
mOutputUri = (Uri) in.readValue(Uri.class.getClassLoader());
@@ -78,6 +89,7 @@ public class ExportKeyringParcel implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mKeyserver);
dest.writeValue(mCanonicalizedPublicKeyringUri);
+ dest.writeValue(mUncachedKeyRing);
dest.writeByte((byte) (mExportSecret ? 0x01 : 0x00));
dest.writeString(mOutputFile);
dest.writeValue(mOutputUri);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
index 1cd76b462..dca2a08c2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.operations.ExportOperation;
import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation;
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
+import org.sufficientlysecure.keychain.operations.RevokeOperation;
import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
@@ -114,6 +115,8 @@ public class KeychainService extends Service implements Progressable {
} else if (inputParcel instanceof SaveKeyringParcel) {
op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis,
mActionCanceled);
+ } else if (inputParcel instanceof RevokeKeyringParcel) {
+ op = new RevokeOperation(outerThis, new ProviderHelper(outerThis), outerThis);
} else if (inputParcel instanceof CertifyActionsParcel) {
op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis,
mActionCanceled);
@@ -135,7 +138,7 @@ public class KeychainService extends Service implements Progressable {
op = new KeybaseVerificationOperation(outerThis, new ProviderHelper(outerThis),
outerThis);
} else {
- return;
+ throw new AssertionError("Unrecognized input parcel in KeychainService!");
}
@SuppressWarnings("unchecked") // this is unchecked, we make sure it's the correct op above!
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index 7c0b7eaef..2a258b7e3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -232,21 +232,21 @@ public class PassphraseCacheService extends Service {
* Internal implementation to get cached passphrase.
*/
private Passphrase getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException {
+ // on "none" key, just do nothing
+ if (masterKeyId == Constants.key.none) {
+ return null;
+ }
+
// passphrase for symmetric encryption?
if (masterKeyId == Constants.key.symmetric) {
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
- Passphrase cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase();
+ CachedPassphrase cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric);
if (cachedPassphrase == null) {
return null;
}
addCachedPassphrase(this, Constants.key.symmetric, Constants.key.symmetric,
- cachedPassphrase, getString(R.string.passp_cache_notif_pwd));
- return cachedPassphrase;
- }
-
- // on "none" key, just do nothing
- if (masterKeyId == Constants.key.none) {
- return null;
+ cachedPassphrase.getPassphrase(), getString(R.string.passp_cache_notif_pwd));
+ return cachedPassphrase.getPassphrase();
}
// try to get master key id which is used as an identifier for cached passphrases
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java
new file mode 100644
index 000000000..02e8fda46
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@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
+ * 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.service;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class RevokeKeyringParcel implements Parcelable {
+
+ final public long mMasterKeyId;
+ final public boolean mUpload;
+ final public String mKeyserver;
+
+ public RevokeKeyringParcel(long masterKeyId, boolean upload, String keyserver) {
+ mMasterKeyId = masterKeyId;
+ mUpload = upload;
+ mKeyserver = keyserver;
+ }
+
+ protected RevokeKeyringParcel(Parcel in) {
+ mMasterKeyId = in.readLong();
+ mUpload = in.readByte() != 0x00;
+ mKeyserver = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mMasterKeyId);
+ dest.writeByte((byte) (mUpload ? 0x01 : 0x00));
+ dest.writeString(mKeyserver);
+ }
+
+ public static final Parcelable.Creator<RevokeKeyringParcel> CREATOR = new Parcelable.Creator<RevokeKeyringParcel>() {
+ @Override
+ public RevokeKeyringParcel createFromParcel(Parcel in) {
+ return new RevokeKeyringParcel(in);
+ }
+
+ @Override
+ public RevokeKeyringParcel[] newArray(int size) {
+ return new RevokeKeyringParcel[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
index e2c4dc542..6959fca56 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
@@ -61,6 +61,15 @@ public class SaveKeyringParcel implements Parcelable {
public ArrayList<String> mRevokeUserIds;
public ArrayList<Long> mRevokeSubKeys;
+ // if these are non-null, PINs will be changed on the card
+ public Passphrase mCardPin;
+ public Passphrase mCardAdminPin;
+
+ // private because they have to be set together with setUpdateOptions
+ private boolean mUpload;
+ private boolean mUploadAtomic;
+ private String mKeyserver;
+
public SaveKeyringParcel() {
reset();
}
@@ -80,6 +89,29 @@ public class SaveKeyringParcel implements Parcelable {
mChangeSubKeys = new ArrayList<>();
mRevokeUserIds = new ArrayList<>();
mRevokeSubKeys = new ArrayList<>();
+ mCardPin = null;
+ mCardAdminPin = null;
+ mUpload = false;
+ mUploadAtomic = false;
+ mKeyserver = null;
+ }
+
+ public void setUpdateOptions(boolean upload, boolean uploadAtomic, String keysever) {
+ mUpload = upload;
+ mUploadAtomic = uploadAtomic;
+ mKeyserver = keysever;
+ }
+
+ public boolean isUpload() {
+ return mUpload;
+ }
+
+ public boolean isUploadAtomic() {
+ return mUploadAtomic;
+ }
+
+ public String getUploadKeyserver() {
+ return mKeyserver;
}
public boolean isEmpty() {
@@ -210,6 +242,7 @@ public class SaveKeyringParcel implements Parcelable {
}
}
+ @SuppressWarnings("unchecked") // we verify the reads against writes in writeToParcel
public SaveKeyringParcel(Parcel source) {
mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
mFingerprint = source.createByteArray();
@@ -225,6 +258,13 @@ public class SaveKeyringParcel implements Parcelable {
mRevokeUserIds = source.createStringArrayList();
mRevokeSubKeys = (ArrayList<Long>) source.readSerializable();
+
+ mCardPin = source.readParcelable(Passphrase.class.getClassLoader());
+ mCardAdminPin = source.readParcelable(Passphrase.class.getClassLoader());
+
+ mUpload = source.readByte() != 0;
+ mUploadAtomic = source.readByte() != 0;
+ mKeyserver = source.readString();
}
@Override
@@ -236,7 +276,7 @@ public class SaveKeyringParcel implements Parcelable {
destination.writeByteArray(mFingerprint);
// yes, null values are ok for parcelables
- destination.writeParcelable(mNewUnlock, 0);
+ destination.writeParcelable(mNewUnlock, flags);
destination.writeStringList(mAddUserIds);
destination.writeSerializable(mAddUserAttribute);
@@ -247,6 +287,13 @@ public class SaveKeyringParcel implements Parcelable {
destination.writeStringList(mRevokeUserIds);
destination.writeSerializable(mRevokeSubKeys);
+
+ destination.writeParcelable(mCardPin, flags);
+ destination.writeParcelable(mCardAdminPin, flags);
+
+ destination.writeByte((byte) (mUpload ? 1 : 0));
+ destination.writeByte((byte) (mUploadAtomic ? 1 : 0));
+ destination.writeString(mKeyserver);
}
public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() {
@@ -274,7 +321,9 @@ public class SaveKeyringParcel implements Parcelable {
out += "mChangeSubKeys: " + mChangeSubKeys + "\n";
out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n";
out += "mRevokeUserIds: " + mRevokeUserIds + "\n";
- out += "mRevokeSubKeys: " + mRevokeSubKeys;
+ out += "mRevokeSubKeys: " + mRevokeSubKeys + "\n";
+ out += "mCardPin: " + mCardPin + "\n";
+ out += "mCardAdminPin: " + mCardAdminPin;
return out;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
index ee7caf2d8..0d8569fe6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
@@ -17,52 +17,87 @@
package org.sufficientlysecure.keychain.service.input;
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
import android.os.Parcel;
import android.os.Parcelable;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Passphrase;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* This is a base class for the input of crypto operations.
*/
public class CryptoInputParcel implements Parcelable {
- final Date mSignatureTime;
- final Passphrase mPassphrase;
+ private Date mSignatureTime;
+ private boolean mHasSignature;
+
+ public Passphrase mPassphrase;
+ // used to supply an explicit proxy to operations that require it
+ // this is not final so it can be added to an existing CryptoInputParcel
+ // (e.g) CertifyOperation with upload might require both passphrase and orbot to be enabled
+ private ParcelableProxy mParcelableProxy;
+
+ // specifies whether passphrases should be cached
+ public boolean mCachePassphrase = true;
// this map contains both decrypted session keys and signed hashes to be
// used in the crypto operation described by this parcel.
private HashMap<ByteBuffer, byte[]> mCryptoData = new HashMap<>();
public CryptoInputParcel() {
- mSignatureTime = new Date();
+ mSignatureTime = null;
mPassphrase = null;
+ mCachePassphrase = true;
}
public CryptoInputParcel(Date signatureTime, Passphrase passphrase) {
+ mHasSignature = true;
mSignatureTime = signatureTime == null ? new Date() : signatureTime;
mPassphrase = passphrase;
+ mCachePassphrase = true;
}
public CryptoInputParcel(Passphrase passphrase) {
- mSignatureTime = new Date();
mPassphrase = passphrase;
+ mCachePassphrase = true;
}
public CryptoInputParcel(Date signatureTime) {
+ mHasSignature = true;
+ mSignatureTime = signatureTime == null ? new Date() : signatureTime;
+ mPassphrase = null;
+ mCachePassphrase = true;
+ }
+
+ public CryptoInputParcel(ParcelableProxy parcelableProxy) {
+ this();
+ mParcelableProxy = parcelableProxy;
+ }
+
+ public CryptoInputParcel(Date signatureTime, boolean cachePassphrase) {
+ mHasSignature = true;
mSignatureTime = signatureTime == null ? new Date() : signatureTime;
mPassphrase = null;
+ mCachePassphrase = cachePassphrase;
+ }
+
+ public CryptoInputParcel(boolean cachePassphrase) {
+ mCachePassphrase = cachePassphrase;
}
protected CryptoInputParcel(Parcel source) {
- mSignatureTime = new Date(source.readLong());
+ mHasSignature = source.readByte() != 0;
+ if (mHasSignature) {
+ mSignatureTime = new Date(source.readLong());
+ }
mPassphrase = source.readParcelable(getClass().getClassLoader());
+ mParcelableProxy = source.readParcelable(getClass().getClassLoader());
+ mCachePassphrase = source.readByte() != 0;
{
int count = source.readInt();
@@ -83,8 +118,13 @@ public class CryptoInputParcel implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(mSignatureTime.getTime());
+ dest.writeByte((byte) (mHasSignature ? 1 : 0));
+ if (mHasSignature) {
+ dest.writeLong(mSignatureTime.getTime());
+ }
dest.writeParcelable(mPassphrase, 0);
+ dest.writeParcelable(mParcelableProxy, 0);
+ dest.writeByte((byte) (mCachePassphrase ? 1 : 0));
dest.writeInt(mCryptoData.size());
for (HashMap.Entry<ByteBuffer, byte[]> entry : mCryptoData.entrySet()) {
@@ -93,6 +133,14 @@ public class CryptoInputParcel implements Parcelable {
}
}
+ public void addParcelableProxy(ParcelableProxy parcelableProxy) {
+ mParcelableProxy = parcelableProxy;
+ }
+
+ public void addSignatureTime(Date signatureTime) {
+ mSignatureTime = signatureTime;
+ }
+
public void addCryptoData(byte[] hash, byte[] signedHash) {
mCryptoData.put(ByteBuffer.wrap(hash), signedHash);
}
@@ -101,6 +149,10 @@ public class CryptoInputParcel implements Parcelable {
mCryptoData.putAll(cachedSessionKeys);
}
+ public ParcelableProxy getParcelableProxy() {
+ return mParcelableProxy;
+ }
+
public Map<ByteBuffer, byte[]> getCryptoData() {
return mCryptoData;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
index efe844145..e4dac3227 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
@@ -1,34 +1,37 @@
package org.sufficientlysecure.keychain.service.input;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.util.Passphrase;
+
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
-import android.os.Parcel;
-import android.os.Parcelable;
-
public class RequiredInputParcel implements Parcelable {
public enum RequiredInputType {
- PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD
+ PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD, ENABLE_ORBOT,
+ UPLOAD_FAIL_RETRY
}
public Date mSignatureTime;
public final RequiredInputType mType;
- public final byte[][] mInputHashes;
+ public final byte[][] mInputData;
public final int[] mSignAlgos;
private Long mMasterKeyId;
private Long mSubKeyId;
- private RequiredInputParcel(RequiredInputType type, byte[][] inputHashes,
+ private RequiredInputParcel(RequiredInputType type, byte[][] inputData,
int[] signAlgos, Date signatureTime, Long masterKeyId, Long subKeyId) {
mType = type;
- mInputHashes = inputHashes;
+ mInputData = inputData;
mSignAlgos = signAlgos;
mSignatureTime = signatureTime;
mMasterKeyId = masterKeyId;
@@ -38,25 +41,25 @@ public class RequiredInputParcel implements Parcelable {
public RequiredInputParcel(Parcel source) {
mType = RequiredInputType.values()[source.readInt()];
- // 0 = none, 1 = both, 2 = only hashes (decrypt)
- int hashTypes = source.readInt();
- if (hashTypes != 0) {
+ // 0 = none, 1 = signAlgos + inputData, 2 = only inputData (decrypt)
+ int inputDataType = source.readInt();
+ if (inputDataType != 0) {
int count = source.readInt();
- mInputHashes = new byte[count][];
- if (hashTypes == 1) {
+ mInputData = new byte[count][];
+ if (inputDataType == 1) {
mSignAlgos = new int[count];
for (int i = 0; i < count; i++) {
- mInputHashes[i] = source.createByteArray();
+ mInputData[i] = source.createByteArray();
mSignAlgos[i] = source.readInt();
}
} else {
mSignAlgos = null;
for (int i = 0; i < count; i++) {
- mInputHashes[i] = source.createByteArray();
+ mInputData[i] = source.createByteArray();
}
}
} else {
- mInputHashes = null;
+ mInputData = null;
mSignAlgos = null;
}
@@ -74,6 +77,15 @@ public class RequiredInputParcel implements Parcelable {
return mSubKeyId;
}
+ public static RequiredInputParcel createRetryUploadOperation() {
+ return new RequiredInputParcel(RequiredInputType.UPLOAD_FAIL_RETRY,
+ null, null, null, 0L, 0L);
+ }
+
+ public static RequiredInputParcel createOrbotRequiredOperation() {
+ return new RequiredInputParcel(RequiredInputType.ENABLE_ORBOT, null, null, null, 0L, 0L);
+ }
+
public static RequiredInputParcel createNfcSignOperation(
long masterKeyId, long subKeyId,
byte[] inputHash, int signAlgo, Date signatureTime) {
@@ -83,9 +95,9 @@ public class RequiredInputParcel implements Parcelable {
}
public static RequiredInputParcel createNfcDecryptOperation(
- long masterKeyId, long subKeyId, byte[] inputHash) {
+ long masterKeyId, long subKeyId, byte[] encryptedSessionKey) {
return new RequiredInputParcel(RequiredInputType.NFC_DECRYPT,
- new byte[][] { inputHash }, null, null, masterKeyId, subKeyId);
+ new byte[][] { encryptedSessionKey }, null, null, masterKeyId, subKeyId);
}
public static RequiredInputParcel createRequiredSignPassphrase(
@@ -119,11 +131,11 @@ public class RequiredInputParcel implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType.ordinal());
- if (mInputHashes != null) {
+ if (mInputData != null) {
dest.writeInt(mSignAlgos != null ? 1 : 2);
- dest.writeInt(mInputHashes.length);
- for (int i = 0; i < mInputHashes.length; i++) {
- dest.writeByteArray(mInputHashes[i]);
+ dest.writeInt(mInputData.length);
+ for (int i = 0; i < mInputData.length; i++) {
+ dest.writeByteArray(mInputData[i]);
if (mSignAlgos != null) {
dest.writeInt(mSignAlgos[i]);
}
@@ -200,7 +212,7 @@ public class RequiredInputParcel implements Parcelable {
throw new AssertionError("operation types must match, this is a progrmming error!");
}
- Collections.addAll(mInputHashes, input.mInputHashes);
+ Collections.addAll(mInputHashes, input.mInputData);
for (int signAlgo : input.mSignAlgos) {
mSignAlgos.add(signAlgo);
}
@@ -215,19 +227,31 @@ public class RequiredInputParcel implements Parcelable {
public static class NfcKeyToCardOperationsBuilder {
ArrayList<byte[]> mSubkeysToExport = new ArrayList<>();
Long mMasterKeyId;
+ byte[] mPin;
+ byte[] mAdminPin;
public NfcKeyToCardOperationsBuilder(Long masterKeyId) {
mMasterKeyId = masterKeyId;
}
public RequiredInputParcel build() {
- byte[][] inputHashes = new byte[mSubkeysToExport.size()][];
- mSubkeysToExport.toArray(inputHashes);
+ byte[][] inputData = new byte[mSubkeysToExport.size() + 2][];
+
+ // encode all subkeys into inputData
+ byte[][] subkeyData = new byte[mSubkeysToExport.size()][];
+ mSubkeysToExport.toArray(subkeyData);
+
+ // first two are PINs
+ inputData[0] = mPin;
+ inputData[1] = mAdminPin;
+ // then subkeys
+ System.arraycopy(subkeyData, 0, inputData, 2, subkeyData.length);
+
ByteBuffer buf = ByteBuffer.wrap(mSubkeysToExport.get(0));
// We need to pass in a subkey here...
return new RequiredInputParcel(RequiredInputType.NFC_MOVE_KEY_TO_CARD,
- inputHashes, null, null, mMasterKeyId, buf.getLong());
+ inputData, null, null, mMasterKeyId, buf.getLong());
}
public void addSubkey(long subkeyId) {
@@ -237,6 +261,14 @@ public class RequiredInputParcel implements Parcelable {
mSubkeysToExport.add(subKeyId);
}
+ public void setPin(Passphrase pin) {
+ mPin = pin.toStringUnsafe().getBytes();
+ }
+
+ public void setAdminPin(Passphrase adminPin) {
+ mAdminPin = adminPin.toStringUnsafe().getBytes();
+ }
+
public void addAll(RequiredInputParcel input) {
if (!mMasterKeyId.equals(input.mMasterKeyId)) {
throw new AssertionError("Master keys must match, this is a programming error!");
@@ -245,7 +277,7 @@ public class RequiredInputParcel implements Parcelable {
throw new AssertionError("Operation types must match, this is a programming error!");
}
- Collections.addAll(mSubkeysToExport, input.mInputHashes);
+ Collections.addAll(mSubkeysToExport, input.mInputData);
}
public boolean isEmpty() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java
new file mode 100644
index 000000000..2d9ac6ee3
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 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;
+
+
+import java.util.ArrayList;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.util.ExportHelper;
+
+public class BackupFragment extends Fragment {
+
+ // This ids for multiple key export.
+ private ArrayList<Long> mIdsForRepeatAskPassphrase;
+ // This index for remembering the number of master key.
+ private int mIndex;
+
+ static final int REQUEST_REPEAT_PASSPHRASE = 1;
+
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.backup_fragment, container, false);
+
+ View backupAll = view.findViewById(R.id.backup_all);
+ View backupPublicKeys = view.findViewById(R.id.backup_public_keys);
+
+ backupAll.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ exportToFile(true);
+ }
+ });
+
+ backupPublicKeys.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ exportToFile(false);
+ }
+ });
+
+ return view;
+ }
+
+ private void exportToFile(boolean includeSecretKeys) {
+ FragmentActivity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ if (!includeSecretKeys) {
+ ExportHelper exportHelper = new ExportHelper(activity);
+ exportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, false);
+ return;
+ }
+
+ new AsyncTask<ContentResolver,Void,ArrayList<Long>>() {
+ @Override
+ protected ArrayList<Long> doInBackground(ContentResolver... resolver) {
+ ArrayList<Long> askPassphraseIds = new ArrayList<>();
+ Cursor cursor = resolver[0].query(
+ KeyRings.buildUnifiedKeyRingsUri(), new String[] {
+ KeyRings.MASTER_KEY_ID,
+ KeyRings.HAS_SECRET,
+ }, KeyRings.HAS_SECRET + " != 0", null, null);
+ try {
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ SecretKeyType secretKeyType = SecretKeyType.fromNum(cursor.getInt(1));
+ switch (secretKeyType) {
+ // all of these make no sense to ask
+ case PASSPHRASE_EMPTY:
+ case GNU_DUMMY:
+ case DIVERT_TO_CARD:
+ case UNAVAILABLE:
+ continue;
+ default: {
+ long keyId = cursor.getLong(0);
+ askPassphraseIds.add(keyId);
+ }
+ }
+ }
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return askPassphraseIds;
+ }
+
+ @Override
+ protected void onPostExecute(ArrayList<Long> askPassphraseIds) {
+ super.onPostExecute(askPassphraseIds);
+ FragmentActivity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ mIdsForRepeatAskPassphrase = askPassphraseIds;
+ mIndex = 0;
+
+ if (mIdsForRepeatAskPassphrase.size() != 0) {
+ startPassphraseActivity();
+ return;
+ }
+
+ ExportHelper exportHelper = new ExportHelper(activity);
+ exportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
+ }
+
+ }.execute(activity.getContentResolver());
+
+ }
+
+ private void startPassphraseActivity() {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ Intent intent = new Intent(activity, PassphraseDialogActivity.class);
+ long masterKeyId = mIdsForRepeatAskPassphrase.get(mIndex++);
+ intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, masterKeyId);
+ startActivityForResult(intent, REQUEST_REPEAT_PASSPHRASE);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+ if (mIndex < mIdsForRepeatAskPassphrase.size()) {
+ startPassphraseActivity();
+ return;
+ }
+
+ ExportHelper exportHelper = new ExportHelper(getActivity());
+ exportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
index 891c2268c..5ca7c6bc7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
@@ -49,13 +49,17 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Preferences;
import java.util.ArrayList;
+import java.util.Date;
public class CertifyKeyFragment
extends CachingCryptoOperationFragment<CertifyActionsParcel, CertifyResult>
@@ -151,7 +155,7 @@ public class CertifyKeyFragment
// make certify image gray, like action icons
ImageView vActionCertifyImage =
(ImageView) view.findViewById(R.id.certify_key_action_certify_image);
- vActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
+ vActionCertifyImage.setColorFilter(FormattingUtils.getColorFromAttr(getActivity(), R.attr.colorTertiaryText),
PorterDuff.Mode.SRC_IN);
View vCertifyButton = view.findViewById(R.id.certify_key_certify_button);
@@ -164,7 +168,7 @@ public class CertifyKeyFragment
Notify.create(getActivity(), getString(R.string.select_key_to_certify),
Notify.Style.ERROR).show();
} else {
- cryptoOperation();
+ cryptoOperation(new CryptoInputParcel(new Date()));
}
}
});
@@ -311,6 +315,11 @@ public class CertifyKeyFragment
CertifyActionsParcel actionsParcel = new CertifyActionsParcel(selectedKeyId);
actionsParcel.mCertifyActions.addAll(certifyActions);
+ if (mUploadKeyCheckbox.isChecked()) {
+ actionsParcel.keyServerUri = Preferences.getPreferences(getActivity())
+ .getPreferredKeyserver();
+ }
+
// cached for next cryptoOperation loop
cacheActionsParcel(actionsParcel);
@@ -318,16 +327,15 @@ public class CertifyKeyFragment
}
@Override
- public void onCryptoOperationSuccess(CertifyResult result) {
+ public void onQueuedOperationSuccess(CertifyResult result) {
+ // protected by Queueing*Fragment
+ Activity activity = getActivity();
+
Intent intent = new Intent();
intent.putExtra(CertifyResult.EXTRA_RESULT, result);
- getActivity().setResult(Activity.RESULT_OK, intent);
- getActivity().finish();
- }
+ activity.setResult(Activity.RESULT_OK, intent);
+ activity.finish();
- @Override
- public void onCryptoOperationCancelled() {
- super.onCryptoOperationCancelled();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
index 7a473e49f..ff5fb7cca 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java
@@ -53,7 +53,7 @@ public class ConsolidateDialogActivity extends FragmentActivity
mRecovery = recovery;
- mConsolidateOpHelper = new CryptoOperationHelper<>(this, this, R.string.progress_importing);
+ mConsolidateOpHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_importing);
mConsolidateOpHelper.cryptoOperation();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
index 505638c7c..83b176680 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
@@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.io.IOException;
@@ -42,7 +43,9 @@ public class CreateKeyActivity extends BaseNfcActivity {
public static final String EXTRA_FIRST_TIME = "first_time";
public static final String EXTRA_ADDITIONAL_EMAILS = "additional_emails";
public static final String EXTRA_PASSPHRASE = "passphrase";
- public static final String EXTRA_USE_SMART_CARD_SETTINGS = "use_smart_card_settings";
+ public static final String EXTRA_CREATE_YUBI_KEY = "create_yubi_key";
+ public static final String EXTRA_YUBI_KEY_PIN = "yubi_key_pin";
+ public static final String EXTRA_YUBI_KEY_ADMIN_PIN = "yubi_key_admin_pin";
public static final String EXTRA_NFC_USER_ID = "nfc_user_id";
public static final String EXTRA_NFC_AID = "nfc_aid";
@@ -55,10 +58,17 @@ public class CreateKeyActivity extends BaseNfcActivity {
ArrayList<String> mAdditionalEmails;
Passphrase mPassphrase;
boolean mFirstTime;
- boolean mUseSmartCardSettings;
+ boolean mCreateYubiKey;
+ Passphrase mYubiKeyPin;
+ Passphrase mYubiKeyAdminPin;
Fragment mCurrentFragment;
+
+ byte[] mScannedFingerprints;
+ byte[] mNfcAid;
+ String mNfcUserId;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -66,13 +76,8 @@ public class CreateKeyActivity extends BaseNfcActivity {
// React on NDEF_DISCOVERED from Manifest
// NOTE: ACTION_NDEF_DISCOVERED and not ACTION_TAG_DISCOVERED like in BaseNfcActivity
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
- try {
- handleTagDiscoveredIntent(getIntent());
- } catch (CardException e) {
- handleNfcError(e);
- } catch (IOException e) {
- handleNfcError(e);
- }
+
+ handleIntentInBackground(getIntent());
setTitle(R.string.title_manage_my_keys);
@@ -88,7 +93,9 @@ public class CreateKeyActivity extends BaseNfcActivity {
mAdditionalEmails = savedInstanceState.getStringArrayList(EXTRA_ADDITIONAL_EMAILS);
mPassphrase = savedInstanceState.getParcelable(EXTRA_PASSPHRASE);
mFirstTime = savedInstanceState.getBoolean(EXTRA_FIRST_TIME);
- mUseSmartCardSettings = savedInstanceState.getBoolean(EXTRA_USE_SMART_CARD_SETTINGS);
+ mCreateYubiKey = savedInstanceState.getBoolean(EXTRA_CREATE_YUBI_KEY);
+ mYubiKeyPin = savedInstanceState.getParcelable(EXTRA_YUBI_KEY_PIN);
+ mYubiKeyAdminPin = savedInstanceState.getParcelable(EXTRA_YUBI_KEY_ADMIN_PIN);
mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
} else {
@@ -98,7 +105,7 @@ public class CreateKeyActivity extends BaseNfcActivity {
mName = intent.getStringExtra(EXTRA_NAME);
mEmail = intent.getStringExtra(EXTRA_EMAIL);
mFirstTime = intent.getBooleanExtra(EXTRA_FIRST_TIME, false);
- mUseSmartCardSettings = intent.getBooleanExtra(EXTRA_USE_SMART_CARD_SETTINGS, false);
+ mCreateYubiKey = intent.getBooleanExtra(EXTRA_CREATE_YUBI_KEY, false);
if (intent.hasExtra(EXTRA_NFC_FINGERPRINTS)) {
byte[] nfcFingerprints = intent.getByteArrayExtra(EXTRA_NFC_FINGERPRINTS);
@@ -106,15 +113,19 @@ public class CreateKeyActivity extends BaseNfcActivity {
byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID);
if (containsKeys(nfcFingerprints)) {
- Fragment frag = CreateKeyYubiKeyImportFragment.newInstance(
+ Fragment frag = CreateYubiKeyImportFragment.newInstance(
nfcFingerprints, nfcAid, nfcUserId);
loadFragment(frag, FragAction.START);
setTitle(R.string.title_import_keys);
} else {
- Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance();
- loadFragment(frag, FragAction.START);
- setTitle(R.string.title_manage_my_keys);
+// Fragment frag = CreateYubiKeyBlankFragment.newInstance();
+// loadFragment(frag, FragAction.START);
+// setTitle(R.string.title_manage_my_keys);
+ Notify.create(this,
+ "YubiKey key creation is currently not supported. Please follow our FAQ.",
+ Notify.Style.ERROR
+ ).show();
}
// done
@@ -136,40 +147,51 @@ public class CreateKeyActivity extends BaseNfcActivity {
}
@Override
- protected void onNfcPerform() throws IOException {
+ protected void doNfcInBackground() throws IOException {
if (mCurrentFragment instanceof NfcListenerFragment) {
- ((NfcListenerFragment) mCurrentFragment).onNfcPerform();
+ ((NfcListenerFragment) mCurrentFragment).doNfcInBackground();
return;
}
- byte[] scannedFingerprints = nfcGetFingerprints();
- byte[] nfcAid = nfcGetAid();
- String userId = nfcGetUserId();
+ mScannedFingerprints = nfcGetFingerprints();
+ mNfcAid = nfcGetAid();
+ mNfcUserId = nfcGetUserId();
+ }
- if (containsKeys(scannedFingerprints)) {
+ @Override
+ protected void onNfcPostExecute() throws IOException {
+ if (mCurrentFragment instanceof NfcListenerFragment) {
+ ((NfcListenerFragment) mCurrentFragment).onNfcPostExecute();
+ return;
+ }
+
+ if (containsKeys(mScannedFingerprints)) {
try {
- long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints);
+ long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mScannedFingerprints);
CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
ring.getMasterKeyId();
Intent intent = new Intent(this, ViewKeyActivity.class);
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, userId);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, scannedFingerprints);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mScannedFingerprints);
startActivity(intent);
finish();
} catch (PgpKeyNotFoundException e) {
- Fragment frag = CreateKeyYubiKeyImportFragment.newInstance(
- scannedFingerprints, nfcAid, userId);
+ Fragment frag = CreateYubiKeyImportFragment.newInstance(
+ mScannedFingerprints, mNfcAid, mNfcUserId);
loadFragment(frag, FragAction.TO_RIGHT);
}
} else {
- Fragment frag = CreateKeyYubiKeyBlankFragment.newInstance();
- loadFragment(frag, FragAction.TO_RIGHT);
+// Fragment frag = CreateYubiKeyBlankFragment.newInstance();
+// loadFragment(frag, FragAction.TO_RIGHT);
+ Notify.create(this,
+ "YubiKey key creation is currently not supported. Please follow our FAQ.",
+ Notify.Style.ERROR
+ ).show();
}
-
}
private boolean containsKeys(byte[] scannedFingerprints) {
@@ -193,7 +215,9 @@ public class CreateKeyActivity extends BaseNfcActivity {
outState.putStringArrayList(EXTRA_ADDITIONAL_EMAILS, mAdditionalEmails);
outState.putParcelable(EXTRA_PASSPHRASE, mPassphrase);
outState.putBoolean(EXTRA_FIRST_TIME, mFirstTime);
- outState.putBoolean(EXTRA_USE_SMART_CARD_SETTINGS, mUseSmartCardSettings);
+ outState.putBoolean(EXTRA_CREATE_YUBI_KEY, mCreateYubiKey);
+ outState.putParcelable(EXTRA_YUBI_KEY_PIN, mYubiKeyPin);
+ outState.putParcelable(EXTRA_YUBI_KEY_ADMIN_PIN, mYubiKeyAdminPin);
}
@Override
@@ -238,7 +262,8 @@ public class CreateKeyActivity extends BaseNfcActivity {
}
interface NfcListenerFragment {
- public void onNfcPerform() throws IOException;
+ public void doNfcInBackground() throws IOException;
+ public void onNfcPostExecute() throws IOException;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java
index 597f04d6b..acb768f55 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
+import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -29,6 +30,7 @@ import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
@@ -37,7 +39,6 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.dialog.AddEmailDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
@@ -201,7 +202,7 @@ public class CreateKeyEmailFragment extends Fragment {
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
- if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
+ if (message.what == AddEmailDialogFragment.MESSAGE_OKAY) {
Bundle data = message.getData();
String email = data.getString(AddEmailDialogFragment.MESSAGE_DATA_EMAIL);
@@ -232,11 +233,35 @@ public class CreateKeyEmailFragment extends Fragment {
mCreateKeyActivity.mEmail = mEmailEdit.getText().toString();
mCreateKeyActivity.mAdditionalEmails = getAdditionalEmails();
- CreateKeyPassphraseFragment frag = CreateKeyPassphraseFragment.newInstance();
- mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ CreateKeyActivity createKeyActivity = ((CreateKeyActivity) getActivity());
+
+ if (createKeyActivity.mCreateYubiKey) {
+ hideKeyboard();
+
+ CreateYubiKeyPinFragment frag = CreateYubiKeyPinFragment.newInstance();
+ mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ } else {
+ CreateKeyPassphraseFragment frag = CreateKeyPassphraseFragment.newInstance();
+ mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ }
}
}
+ 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);
+ }
+
private ArrayList<String> getAdditionalEmails() {
ArrayList<String> emails = new ArrayList<>();
for (EmailAdapter.ViewModel holder : mAdditionalEmailModels) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
index e67715988..739eb3e35 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -17,6 +17,10 @@
package org.sufficientlysecure.keychain.ui;
+
+import java.util.Date;
+import java.util.Iterator;
+
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
@@ -44,13 +48,13 @@ import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
-import java.util.Iterator;
-
public class CreateKeyFinalFragment extends Fragment {
public static final int REQUEST_EDIT_KEY = 0x00008007;
@@ -69,8 +73,14 @@ public class CreateKeyFinalFragment extends Fragment {
private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mCreateOpHelper;
private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mMoveToCardOpHelper;
+ // queued results which may trigger delayed actions
+ private EditKeyResult mQueuedSaveKeyResult;
+ private OperationResult mQueuedFinishResult;
+ private EditKeyResult mQueuedDisplayResult;
+
public static CreateKeyFinalFragment newInstance() {
CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
+ frag.setRetainInstance(true);
Bundle args = new Bundle();
frag.setArguments(args);
@@ -178,7 +188,7 @@ public class CreateKeyFinalFragment extends Fragment {
if (mSaveKeyringParcel == null) {
mSaveKeyringParcel = new SaveKeyringParcel();
- if (createKeyActivity.mUseSmartCardSettings) {
+ if (createKeyActivity.mCreateYubiKey) {
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA,
2048, null, KeyFlags.SIGN_DATA | KeyFlags.CERTIFY_OTHER, 0L));
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA,
@@ -187,6 +197,9 @@ public class CreateKeyFinalFragment extends Fragment {
2048, null, KeyFlags.AUTHENTICATION, 0L));
mEditText.setText(R.string.create_key_custom);
mEditButton.setEnabled(false);
+
+ // use empty passphrase
+ mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel(new Passphrase(), null);
} else {
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA,
4096, null, KeyFlags.CERTIFY_OTHER, 0L));
@@ -194,6 +207,10 @@ public class CreateKeyFinalFragment extends Fragment {
4096, null, KeyFlags.SIGN_DATA, 0L));
mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Algorithm.RSA,
4096, null, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L));
+
+ mSaveKeyringParcel.mNewUnlock = createKeyActivity.mPassphrase != null
+ ? new ChangeUnlockParcel(createKeyActivity.mPassphrase, null)
+ : null;
}
String userId = KeyRing.createUserId(
new KeyRing.UserId(createKeyActivity.mName, createKeyActivity.mEmail, null)
@@ -209,14 +226,44 @@ public class CreateKeyFinalFragment extends Fragment {
mSaveKeyringParcel.mAddUserIds.add(thisUserId);
}
}
- mSaveKeyringParcel.mNewUnlock = createKeyActivity.mPassphrase != null
- ? new ChangeUnlockParcel(createKeyActivity.mPassphrase, null)
- : null;
}
+
+ // handle queued actions
+
+ if (mQueuedFinishResult != null) {
+ finishWithResult(mQueuedFinishResult);
+ return;
+ }
+
+ if (mQueuedDisplayResult != null) {
+ try {
+ displayResult(mQueuedDisplayResult);
+ } finally {
+ // clear after operation, note that this may drop the operation if it didn't
+ // work when called from here!
+ mQueuedDisplayResult = null;
+ }
+ }
+
+ if (mQueuedSaveKeyResult != null) {
+ try {
+ uploadKey(mQueuedSaveKeyResult);
+ } finally {
+ // see above
+ mQueuedSaveKeyResult = null;
+ }
+ }
+
}
private void createKey() {
- final CreateKeyActivity createKeyActivity = (CreateKeyActivity) getActivity();
+ CreateKeyActivity activity = (CreateKeyActivity) getActivity();
+ if (activity == null) {
+ // this is a ui-triggered action, nvm if it fails while detached!
+ return;
+ }
+
+ final boolean createYubiKey = activity.mCreateYubiKey;
CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult> createKeyCallback
= new CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult>() {
@@ -228,7 +275,7 @@ public class CreateKeyFinalFragment extends Fragment {
@Override
public void onCryptoOperationSuccess(EditKeyResult result) {
- if (createKeyActivity.mUseSmartCardSettings) {
+ if (createYubiKey) {
moveToCard(result);
return;
}
@@ -239,10 +286,7 @@ public class CreateKeyFinalFragment extends Fragment {
return;
}
- Intent data = new Intent();
- data.putExtra(OperationResult.EXTRA_RESULT, result);
- getActivity().setResult(Activity.RESULT_OK, data);
- getActivity().finish();
+ finishWithResult(result);
}
@Override
@@ -252,7 +296,7 @@ public class CreateKeyFinalFragment extends Fragment {
@Override
public void onCryptoOperationError(EditKeyResult result) {
- result.createNotify(getActivity()).show();
+ displayResult(result);
}
@Override
@@ -261,16 +305,25 @@ public class CreateKeyFinalFragment extends Fragment {
}
};
- mCreateOpHelper = new CryptoOperationHelper<>(this, createKeyCallback,
- R.string.progress_building_key);
+ mCreateOpHelper = new CryptoOperationHelper<>(1, this, createKeyCallback, R.string.progress_building_key);
mCreateOpHelper.cryptoOperation();
}
+ private void displayResult(EditKeyResult result) {
+ Activity activity = getActivity();
+ if (activity == null) {
+ mQueuedDisplayResult = result;
+ return;
+ }
+ result.createNotify(activity).show();
+ }
+
private void moveToCard(final EditKeyResult saveKeyResult) {
- CachedPublicKeyRing key = (new ProviderHelper(getActivity()))
- .getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
+ CreateKeyActivity activity = (CreateKeyActivity) getActivity();
final SaveKeyringParcel changeKeyringParcel;
+ CachedPublicKeyRing key = (new ProviderHelper(activity))
+ .getCachedPublicKeyRing(saveKeyResult.mMasterKeyId);
try {
changeKeyringParcel = new SaveKeyringParcel(key.getMasterKeyId(), key.getFingerprint());
} catch (PgpKeyNotFoundException e) {
@@ -278,9 +331,10 @@ public class CreateKeyFinalFragment extends Fragment {
return;
}
- Cursor cursor = getActivity().getContentResolver().query(
+ // define subkeys that should be moved to the card
+ Cursor cursor = activity.getContentResolver().query(
KeychainContract.Keys.buildKeysUri(changeKeyringParcel.mMasterKeyId),
- new String[]{KeychainContract.Keys.KEY_ID,}, null, null, null
+ new String[] { KeychainContract.Keys.KEY_ID, }, null, null, null
);
try {
while (cursor != null && cursor.moveToNext()) {
@@ -293,6 +347,10 @@ public class CreateKeyFinalFragment extends Fragment {
}
}
+ // define new PIN and Admin PIN for the card
+ changeKeyringParcel.mCardPin = activity.mYubiKeyPin;
+ changeKeyringParcel.mCardAdminPin = activity.mYubiKeyAdminPin;
+
CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult> callback
= new CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult>() {
@@ -326,10 +384,7 @@ public class CreateKeyFinalFragment extends Fragment {
return;
}
- Intent data = new Intent();
- data.putExtra(OperationResult.EXTRA_RESULT, saveKeyResult);
- getActivity().setResult(Activity.RESULT_OK, data);
- getActivity().finish();
+ finishWithResult(saveKeyResult);
}
@Override
@@ -339,16 +394,22 @@ public class CreateKeyFinalFragment extends Fragment {
};
- mMoveToCardOpHelper = new CryptoOperationHelper<>(this, callback, R.string.progress_modify);
- mMoveToCardOpHelper.cryptoOperation();
+ mMoveToCardOpHelper = new CryptoOperationHelper<>(2, this, callback, R.string.progress_modify);
+ mMoveToCardOpHelper.cryptoOperation(new CryptoInputParcel(new Date()));
}
private void uploadKey(final EditKeyResult saveKeyResult) {
+ Activity activity = getActivity();
+ // if the activity is gone at this point, there is nothing we can do!
+ if (activity == null) {
+ mQueuedSaveKeyResult = saveKeyResult;
+ return;
+ }
+
// set data uri as path to keyring
- final Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(
- saveKeyResult.mMasterKeyId);
+ final Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(saveKeyResult.mMasterKeyId);
// upload to favorite keyserver
- final String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver();
+ final String keyserver = Preferences.getPreferences(activity).getPreferredKeyserver();
CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult> callback
= new CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult>() {
@@ -374,14 +435,8 @@ public class CreateKeyFinalFragment extends Fragment {
}
public void handleResult(ExportResult result) {
- // TODO: ExportOperation UPLOAD_KEYSERVER needs logs!
- // TODO: then merge logs here!
- //saveKeyResult.getLog().add(result, 0);
-
- Intent data = new Intent();
- data.putExtra(OperationResult.EXTRA_RESULT, saveKeyResult);
- getActivity().setResult(Activity.RESULT_OK, data);
- getActivity().finish();
+ saveKeyResult.getLog().add(result, 0);
+ finishWithResult(saveKeyResult);
}
@Override
@@ -390,9 +445,21 @@ public class CreateKeyFinalFragment extends Fragment {
}
};
-
- mUploadOpHelper = new CryptoOperationHelper<>(this, callback, R.string.progress_uploading);
+ mUploadOpHelper = new CryptoOperationHelper<>(3, this, callback, R.string.progress_uploading);
mUploadOpHelper.cryptoOperation();
}
+ public void finishWithResult(OperationResult result) {
+ Activity activity = getActivity();
+ if (activity == null) {
+ mQueuedFinishResult = result;
+ return;
+ }
+
+ Intent data = new Intent();
+ data.putExtra(OperationResult.EXTRA_RESULT, result);
+ activity.setResult(Activity.RESULT_OK, data);
+ activity.finish();
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java
index 3379e0a6d..d858fd6ec 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java
@@ -21,6 +21,8 @@ import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.view.LayoutInflater;
@@ -79,19 +81,10 @@ public class CreateKeyPassphraseFragment extends Fragment {
return output;
}
- private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
+ private static boolean areEditTextsEqual(EditText editText1, EditText editText2) {
Passphrase p1 = new Passphrase(editText1);
Passphrase p2 = new Passphrase(editText2);
- boolean output = (p1.equals(p2));
-
- if (!output) {
- editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
- editText2.requestFocus();
- } else {
- editText2.setError(null);
- }
-
- return output;
+ return (p1.equals(p2));
}
@Override
@@ -107,8 +100,8 @@ public class CreateKeyPassphraseFragment extends Fragment {
// initial values
// TODO: using String here is unsafe...
if (mCreateKeyActivity.mPassphrase != null) {
- mPassphraseEdit.setText(new String(mCreateKeyActivity.mPassphrase.getCharArray()));
- mPassphraseEditAgain.setText(new String(mCreateKeyActivity.mPassphrase.getCharArray()));
+ mPassphraseEdit.setText(mCreateKeyActivity.mPassphrase.toStringUnsafe());
+ mPassphraseEditAgain.setText(mCreateKeyActivity.mPassphrase.toStringUnsafe());
}
mPassphraseEdit.requestFocus();
@@ -137,6 +130,35 @@ public class CreateKeyPassphraseFragment extends Fragment {
}
});
+ TextWatcher textWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ if (!isEditTextNotEmpty(getActivity(), mPassphraseEdit)) {
+ mPassphraseEditAgain.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+ return;
+ }
+
+ if (areEditTextsEqual(mPassphraseEdit, mPassphraseEditAgain)) {
+ mPassphraseEditAgain.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_stat_retyped_ok, 0);
+ } else {
+ mPassphraseEditAgain.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_stat_retyped_bad, 0);
+ }
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ }
+ };
+
+ mPassphraseEdit.addTextChangedListener(textWatcher);
+ mPassphraseEditAgain.addTextChangedListener(textWatcher);
return view;
}
@@ -153,9 +175,15 @@ public class CreateKeyPassphraseFragment extends Fragment {
}
private void nextClicked() {
- if (isEditTextNotEmpty(getActivity(), mPassphraseEdit)
- && areEditTextsEqual(getActivity(), mPassphraseEdit, mPassphraseEditAgain)) {
+ if (isEditTextNotEmpty(getActivity(), mPassphraseEdit)) {
+
+ if (!areEditTextsEqual(mPassphraseEdit, mPassphraseEditAgain)) {
+ mPassphraseEditAgain.setError(getActivity().getApplicationContext().getString(R.string.create_key_passphrases_not_equal));
+ mPassphraseEditAgain.requestFocus();
+ return;
+ }
+ mPassphraseEditAgain.setError(null);
// save state
mCreateKeyActivity.mPassphrase = new Passphrase(mPassphraseEdit);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java
index 1a844e6e4..cd97ef108 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java
@@ -81,7 +81,7 @@ public class CreateKeyStartFragment extends Fragment {
mYubiKey.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- CreateKeyYubiKeyWaitFragment frag = new CreateKeyYubiKeyWaitFragment();
+ CreateYubiKeyWaitFragment frag = new CreateYubiKeyWaitFragment();
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
}
});
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyBlankFragment.java
index 6df340636..5b13dc88e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyBlankFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyBlankFragment.java
@@ -27,7 +27,7 @@ import android.view.ViewGroup;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
-public class CreateKeyYubiKeyBlankFragment extends Fragment {
+public class CreateYubiKeyBlankFragment extends Fragment {
CreateKeyActivity mCreateKeyActivity;
View mBackButton;
@@ -36,8 +36,8 @@ public class CreateKeyYubiKeyBlankFragment extends Fragment {
/**
* Creates new instance of this fragment
*/
- public static CreateKeyYubiKeyBlankFragment newInstance() {
- CreateKeyYubiKeyBlankFragment frag = new CreateKeyYubiKeyBlankFragment();
+ public static CreateYubiKeyBlankFragment newInstance() {
+ CreateYubiKeyBlankFragment frag = new CreateYubiKeyBlankFragment();
Bundle args = new Bundle();
@@ -81,7 +81,7 @@ public class CreateKeyYubiKeyBlankFragment extends Fragment {
}
private void nextClicked() {
- mCreateKeyActivity.mUseSmartCardSettings = true;
+ mCreateKeyActivity.mCreateYubiKey = true;
CreateKeyNameFragment frag = CreateKeyNameFragment.newInstance();
mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java
index 8de874ec5..d88e6b9f9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyImportFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -39,13 +40,13 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Preferences;
-public class CreateKeyYubiKeyImportFragment
- extends CryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
+public class CreateYubiKeyImportFragment
+ extends QueueingCryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
implements NfcListenerFragment {
private static final String ARG_FINGERPRINT = "fingerprint";
@@ -68,7 +69,7 @@ public class CreateKeyYubiKeyImportFragment
public static Fragment newInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) {
- CreateKeyYubiKeyImportFragment frag = new CreateKeyYubiKeyImportFragment();
+ CreateYubiKeyImportFragment frag = new CreateYubiKeyImportFragment();
Bundle args = new Bundle();
args.putByteArray(ARG_FINGERPRINT, scannedFingerprints);
@@ -195,7 +196,7 @@ public class CreateKeyYubiKeyImportFragment
}
@Override
- public void onNfcPerform() throws IOException {
+ public void doNfcInBackground() throws IOException {
mNfcFingerprints = mCreateKeyActivity.nfcGetFingerprints();
mNfcAid = mCreateKeyActivity.nfcGetAid();
@@ -204,10 +205,14 @@ public class CreateKeyYubiKeyImportFragment
byte[] fp = new byte[20];
ByteBuffer.wrap(fp).put(mNfcFingerprints, 0, 20);
mNfcFingerprint = KeyFormattingUtils.convertFingerprintToHex(fp);
+ }
+
+ @Override
+ public void onNfcPostExecute() throws IOException {
setData();
- refreshSearch();
+ refreshSearch();
}
@Override
@@ -216,14 +221,17 @@ public class CreateKeyYubiKeyImportFragment
}
@Override
- public void onCryptoOperationSuccess(ImportKeyResult result) {
+ public void onQueuedOperationSuccess(ImportKeyResult result) {
long[] masterKeyIds = result.getImportedMasterKeyIds();
if (masterKeyIds.length == 0) {
super.onCryptoOperationError(result);
return;
}
- Intent intent = new Intent(getActivity(), ViewKeyActivity.class);
+ // null-protected from Queueing*Fragment
+ Activity activity = getActivity();
+
+ Intent intent = new Intent(activity, ViewKeyActivity.class);
// use the imported masterKeyId, not the one from the yubikey, because
// that one might* just have been a subkey of the imported key
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyIds[0]));
@@ -232,6 +240,6 @@ public class CreateKeyYubiKeyImportFragment
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent);
- getActivity().finish();
+ activity.finish();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java
new file mode 100644
index 000000000..a793b31f2
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.app.Activity;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
+import org.sufficientlysecure.keychain.util.Passphrase;
+
+import java.security.SecureRandom;
+
+public class CreateYubiKeyPinFragment extends Fragment {
+
+ // view
+ CreateKeyActivity mCreateKeyActivity;
+ TextView mPin;
+ TextView mAdminPin;
+ View mBackButton;
+ View mNextButton;
+
+ /**
+ * Creates new instance of this fragment
+ */
+ public static CreateYubiKeyPinFragment newInstance() {
+ CreateYubiKeyPinFragment frag = new CreateYubiKeyPinFragment();
+
+ Bundle args = new Bundle();
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.create_yubi_key_pin_fragment, container, false);
+
+ mPin = (TextView) view.findViewById(R.id.create_yubi_key_pin);
+ mAdminPin = (TextView) view.findViewById(R.id.create_yubi_key_admin_pin);
+ mBackButton = view.findViewById(R.id.create_key_back_button);
+ mNextButton = view.findViewById(R.id.create_key_next_button);
+
+ if (mCreateKeyActivity.mYubiKeyPin == null) {
+ new AsyncTask<Void, Void, Pair<Passphrase, Passphrase>>() {
+ @Override
+ protected Pair<Passphrase, Passphrase> doInBackground(Void... unused) {
+ SecureRandom secureRandom = new SecureRandom();
+ // min = 6, we choose 6
+ String pin = "" + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9);
+ // min = 8, we choose 10, but 6 are equals the PIN
+ String adminPin = pin + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9)
+ + secureRandom.nextInt(9);
+
+ return new Pair<>(new Passphrase(pin), new Passphrase(adminPin));
+ }
+
+ @Override
+ protected void onPostExecute(Pair<Passphrase, Passphrase> pair) {
+ mCreateKeyActivity.mYubiKeyPin = pair.first;
+ mCreateKeyActivity.mYubiKeyAdminPin = pair.second;
+
+ mPin.setText(mCreateKeyActivity.mYubiKeyPin.toStringUnsafe());
+ mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe());
+ }
+ }.execute();
+ } else {
+ mPin.setText(mCreateKeyActivity.mYubiKeyPin.toStringUnsafe());
+ mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe());
+ }
+
+ mBackButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ back();
+ }
+ });
+ mNextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ nextClicked();
+ }
+ });
+
+
+ return view;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mCreateKeyActivity = (CreateKeyActivity) getActivity();
+ }
+
+
+ private void nextClicked() {
+ CreateYubiKeyPinRepeatFragment frag = CreateYubiKeyPinRepeatFragment.newInstance();
+ mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ }
+
+ private void back() {
+ mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java
new file mode 100644
index 000000000..2e752e609
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
+
+public class CreateYubiKeyPinRepeatFragment extends Fragment {
+
+ // view
+ CreateKeyActivity mCreateKeyActivity;
+ EditText mPin;
+ EditText mAdminPin;
+ View mBackButton;
+ View mNextButton;
+
+ /**
+ * Creates new instance of this fragment
+ */
+ public static CreateYubiKeyPinRepeatFragment newInstance() {
+ CreateYubiKeyPinRepeatFragment frag = new CreateYubiKeyPinRepeatFragment();
+
+ Bundle args = new Bundle();
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ /**
+ * Checks if text of given EditText is not empty. If it is empty an error is
+ * set and the EditText gets the focus.
+ *
+ * @param context
+ * @param editText
+ * @return true if EditText is not empty
+ */
+ private static boolean isEditTextNotEmpty(Context context, EditText editText) {
+ boolean output = true;
+ if (editText.getText().length() == 0) {
+ editText.setError(context.getString(R.string.create_key_empty));
+ editText.requestFocus();
+ output = false;
+ } else {
+ editText.setError(null);
+ }
+
+ return output;
+ }
+
+ private static boolean checkPin(Context context, EditText editText1, String pin) {
+ boolean output = editText1.getText().toString().equals(pin);
+
+ if (!output) {
+ editText1.setError(context.getString(R.string.create_key_yubi_key_pin_not_correct));
+ editText1.requestFocus();
+ } else {
+ editText1.setError(null);
+ }
+
+ return output;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.create_yubi_key_pin_repeat_fragment, container, false);
+
+ mPin = (EditText) view.findViewById(R.id.create_yubi_key_pin_repeat);
+ mAdminPin = (EditText) view.findViewById(R.id.create_yubi_key_admin_pin_repeat);
+ mBackButton = view.findViewById(R.id.create_key_back_button);
+ mNextButton = view.findViewById(R.id.create_key_next_button);
+
+ mPin.requestFocus();
+ mBackButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ back();
+ }
+ });
+ mNextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ nextClicked();
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mCreateKeyActivity = (CreateKeyActivity) getActivity();
+ }
+
+ private void back() {
+ hideKeyboard();
+ mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
+ }
+
+ private void nextClicked() {
+ if (isEditTextNotEmpty(getActivity(), mPin)
+ && checkPin(getActivity(), mPin, mCreateKeyActivity.mYubiKeyPin.toStringUnsafe())
+ && isEditTextNotEmpty(getActivity(), mAdminPin)
+ && checkPin(getActivity(), mAdminPin, mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe())) {
+
+ CreateKeyFinalFragment frag = CreateKeyFinalFragment.newInstance();
+ hideKeyboard();
+ mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ }
+ }
+
+ 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);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyWaitFragment.java
index 0e2dd2531..d45195512 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiKeyWaitFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyWaitFragment.java
@@ -28,7 +28,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
-public class CreateKeyYubiKeyWaitFragment extends Fragment {
+public class CreateYubiKeyWaitFragment extends Fragment {
CreateKeyActivity mCreateKeyActivity;
View mBackButton;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 04f54f151..e581e069b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -49,13 +49,7 @@ public class DecryptActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(Activity.RESULT_CANCELED);
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_CANCELED, false);
// Handle intent actions
handleActions(savedInstanceState, getIntent());
@@ -158,7 +152,6 @@ public class DecryptActivity extends BaseActivity {
}
-
} catch (IOException e) {
Toast.makeText(this, R.string.error_reading_text, Toast.LENGTH_LONG).show();
finish();
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 4eb8cd5e8..aaf337f42 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
@@ -19,15 +19,11 @@ package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
-import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
import android.support.v4.app.Fragment;
-import android.os.Parcelable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@@ -52,7 +48,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
-import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
@@ -189,7 +184,7 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
}
};
- mImportOpHelper = new CryptoOperationHelper<>(this, callback, R.string.progress_importing);
+ mImportOpHelper = new CryptoOperationHelper<>(1, this, callback, R.string.progress_importing);
mImportOpHelper.cryptoOperation();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
index 96767463e..567589821 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
@@ -65,12 +65,11 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
-import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
// this import NEEDS to be above the ViewModel one, or it won't compile! (as of 06/06/15)
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.StatusHolder;
import org.sufficientlysecure.keychain.ui.DecryptListFragment.DecryptFilesAdapter.ViewModel;
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -81,18 +80,21 @@ import org.sufficientlysecure.keychain.util.ParcelableHashMap;
public class DecryptListFragment
- extends CryptoOperationFragment<PgpDecryptVerifyInputParcel,DecryptVerifyResult>
+ extends QueueingCryptoOperationFragment<PgpDecryptVerifyInputParcel,DecryptVerifyResult>
implements OnMenuItemClickListener {
public static final String ARG_INPUT_URIS = "input_uris";
public static final String ARG_OUTPUT_URIS = "output_uris";
+ public static final String ARG_CANCELLED_URIS = "cancelled_uris";
public static final String ARG_RESULTS = "results";
private static final int REQUEST_CODE_OUTPUT = 0x00007007;
+ public static final String ARG_CURRENT_URI = "current_uri";
private ArrayList<Uri> mInputUris;
private HashMap<Uri, Uri> mOutputUris;
private ArrayList<Uri> mPendingInputUris;
+ private ArrayList<Uri> mCancelledInputUris;
private Uri mCurrentInputUri;
@@ -111,6 +113,10 @@ public class DecryptListFragment
return frag;
}
+ public DecryptListFragment() {
+ super(null);
+ }
+
/**
* Inflate the layout for this fragment
*/
@@ -152,6 +158,8 @@ public class DecryptListFragment
outState.putParcelable(ARG_RESULTS, new ParcelableHashMap<>(results));
outState.putParcelable(ARG_OUTPUT_URIS, new ParcelableHashMap<>(mOutputUris));
+ outState.putParcelableArrayList(ARG_CANCELLED_URIS, mCancelledInputUris);
+ outState.putParcelable(ARG_CURRENT_URI, mCurrentInputUri);
}
@@ -162,25 +170,45 @@ public class DecryptListFragment
Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
ArrayList<Uri> inputUris = getArguments().getParcelableArrayList(ARG_INPUT_URIS);
+ ArrayList<Uri> cancelledUris = args.getParcelableArrayList(ARG_CANCELLED_URIS);
ParcelableHashMap<Uri,Uri> outputUris = args.getParcelable(ARG_OUTPUT_URIS);
ParcelableHashMap<Uri,DecryptVerifyResult> results = args.getParcelable(ARG_RESULTS);
+ Uri currentInputUri = args.getParcelable(ARG_CURRENT_URI);
- displayInputUris(inputUris,
+ displayInputUris(inputUris, currentInputUri, cancelledUris,
outputUris != null ? outputUris.getMap() : null,
results != null ? results.getMap() : null
);
}
- private void displayInputUris(ArrayList<Uri> inputUris, HashMap<Uri,Uri> outputUris,
+ private void displayInputUris(ArrayList<Uri> inputUris, Uri currentInputUri,
+ ArrayList<Uri> cancelledUris, HashMap<Uri,Uri> outputUris,
HashMap<Uri,DecryptVerifyResult> results) {
mInputUris = inputUris;
+ mCurrentInputUri = currentInputUri;
mOutputUris = outputUris != null ? outputUris : new HashMap<Uri,Uri>(inputUris.size());
+ mCancelledInputUris = cancelledUris != null ? cancelledUris : new ArrayList<Uri>();
mPendingInputUris = new ArrayList<>();
- for (Uri uri : inputUris) {
+ for (final Uri uri : inputUris) {
mAdapter.add(uri);
+
+ if (uri.equals(mCurrentInputUri)) {
+ continue;
+ }
+
+ if (mCancelledInputUris.contains(uri)) {
+ mAdapter.setCancelled(uri, new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ retryUri(uri);
+ }
+ });
+ continue;
+ }
+
if (results != null && results.containsKey(uri)) {
processResult(uri, results.get(uri));
} else {
@@ -189,16 +217,9 @@ public class DecryptListFragment
}
}
- cryptoOperation();
- }
-
- private String removeEncryptedAppend(String name) {
- if (name.endsWith(Constants.FILE_EXTENSION_ASC)
- || name.endsWith(Constants.FILE_EXTENSION_PGP_MAIN)
- || name.endsWith(Constants.FILE_EXTENSION_PGP_ALTERNATE)) {
- return name.substring(0, name.length() - 4);
+ if (mCurrentInputUri == null) {
+ cryptoOperation();
}
- return name;
}
private void askForOutputFilename(Uri inputUri, String originalFilename, String mimeType) {
@@ -249,17 +270,13 @@ public class DecryptListFragment
}
@Override
- protected void cryptoOperation(CryptoInputParcel cryptoInput) {
- super.cryptoOperation(cryptoInput, false);
- }
-
- @Override
public boolean onCryptoSetProgress(String msg, int progress, int max) {
mAdapter.setProgress(mCurrentInputUri, progress, max, msg);
return true;
}
+
@Override
- public void onCryptoOperationError(DecryptVerifyResult result) {
+ public void onQueuedOperationError(DecryptVerifyResult result) {
final Uri uri = mCurrentInputUri;
mCurrentInputUri = null;
@@ -269,7 +286,7 @@ public class DecryptListFragment
}
@Override
- public void onCryptoOperationSuccess(DecryptVerifyResult result) {
+ public void onQueuedOperationSuccess(DecryptVerifyResult result) {
Uri uri = mCurrentInputUri;
mCurrentInputUri = null;
@@ -278,6 +295,25 @@ public class DecryptListFragment
cryptoOperation();
}
+ @Override
+ public void onCryptoOperationCancelled() {
+ super.onCryptoOperationCancelled();
+
+ final Uri uri = mCurrentInputUri;
+ mCurrentInputUri = null;
+
+ mCancelledInputUris.add(uri);
+ mAdapter.setCancelled(uri, new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ retryUri(uri);
+ }
+ });
+
+ cryptoOperation();
+
+ }
+
private void processResult(final Uri uri, final DecryptVerifyResult result) {
new AsyncTask<Void, Void, Drawable>() {
@@ -304,7 +340,7 @@ public class DecryptListFragment
}
final Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setType(type);
+ intent.setDataAndType(outputUri, type);
final List<ResolveInfo> matches =
context.getPackageManager().queryIntentActivities(intent, 0);
@@ -361,6 +397,22 @@ public class DecryptListFragment
}
+ public void retryUri(Uri uri) {
+
+ // never interrupt running operations!
+ if (mCurrentInputUri != null) {
+ return;
+ }
+
+ // un-cancel this one
+ mCancelledInputUris.remove(uri);
+ mPendingInputUris.add(uri);
+ mAdapter.setCancelled(uri, null);
+
+ cryptoOperation();
+
+ }
+
public void displayWithViewIntent(final Uri uri) {
Activity activity = getActivity();
if (activity == null || mCurrentInputUri != null) {
@@ -539,12 +591,14 @@ public class DecryptListFragment
int mProgress, mMax;
String mProgressMsg;
+ OnClickListener mCancelled;
ViewModel(Context context, Uri uri) {
mContext = context;
mInputUri = uri;
mProgress = 0;
mMax = 100;
+ mCancelled = null;
}
void addResult(DecryptVerifyResult result) {
@@ -564,6 +618,10 @@ public class DecryptListFragment
return mResult != null;
}
+ void setCancelled(OnClickListener retryListener) {
+ mCancelled = retryListener;
+ }
+
void setProgress(int progress, int max, String msg) {
if (msg != null) {
mProgressMsg = msg;
@@ -621,6 +679,11 @@ public class DecryptListFragment
// - replace the contents of the view with that element
final ViewModel model = mDataset.get(position);
+ if (model.mCancelled != null) {
+ bindItemCancelled(holder, model);
+ return;
+ }
+
if (!model.hasResult()) {
bindItemProgress(holder, model);
return;
@@ -634,6 +697,14 @@ public class DecryptListFragment
}
+ private void bindItemCancelled(ViewHolder holder, ViewModel model) {
+ if (holder.vAnimator.getDisplayedChild() != 3) {
+ holder.vAnimator.setDisplayedChild(3);
+ }
+
+ holder.vCancelledRetry.setOnClickListener(model.mCancelled);
+ }
+
private void bindItemProgress(ViewHolder holder, ViewModel model) {
if (holder.vAnimator.getDisplayedChild() != 0) {
holder.vAnimator.setDisplayedChild(0);
@@ -749,6 +820,13 @@ public class DecryptListFragment
notifyItemChanged(pos);
}
+ public void setCancelled(Uri uri, OnClickListener retryListener) {
+ ViewModel newModel = new ViewModel(mContext, uri);
+ int pos = mDataset.indexOf(newModel);
+ mDataset.get(pos).setCancelled(retryListener);
+ notifyItemChanged(pos);
+ }
+
public void addResult(Uri uri, DecryptVerifyResult result, Drawable icon,
OnClickListener onFileClick, OnClickListener onKeyClick) {
@@ -796,6 +874,8 @@ public class DecryptListFragment
public TextView vErrorMsg;
public ImageView vErrorViewLog;
+ public ImageView vCancelledRetry;
+
public ViewHolder(View itemView) {
super(itemView);
@@ -824,6 +904,8 @@ public class DecryptListFragment
vErrorMsg = (TextView) itemView.findViewById(R.id.result_error_msg);
vErrorViewLog = (ImageView) itemView.findViewById(R.id.result_error_log);
+ vCancelledRetry = (ImageView) itemView.findViewById(R.id.cancel_retry);
+
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java
new file mode 100644
index 000000000..b22053df1
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@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
+ * 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;
+
+import android.app.Activity;
+import android.support.v7.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.operations.results.DeleteResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.operations.results.RevokeResult;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.DeleteKeyringParcel;
+import org.sufficientlysecure.keychain.service.RevokeKeyringParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
+import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.Date;
+import java.util.HashMap;
+
+public class DeleteKeyDialogActivity extends FragmentActivity {
+ public static final String EXTRA_DELETE_MASTER_KEY_IDS = "extra_delete_master_key_ids";
+ public static final String EXTRA_HAS_SECRET = "extra_has_secret";
+ public static final String EXTRA_KEYSERVER = "extra_keyserver";
+
+ private CryptoOperationHelper<DeleteKeyringParcel, DeleteResult> mDeleteOpHelper;
+ private CryptoOperationHelper<RevokeKeyringParcel, RevokeResult> mRevokeOpHelper;
+
+ private long[] mMasterKeyIds;
+ private boolean mHasSecret;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mDeleteOpHelper = new CryptoOperationHelper<>(1, DeleteKeyDialogActivity.this,
+ getDeletionCallback(), R.string.progress_deleting);
+
+ mRevokeOpHelper = new CryptoOperationHelper<>(2, this,
+ getRevocationCallback(), R.string.progress_revoking_uploading);
+
+ mMasterKeyIds = getIntent().getLongArrayExtra(EXTRA_DELETE_MASTER_KEY_IDS);
+ mHasSecret = getIntent().getBooleanExtra(EXTRA_HAS_SECRET, false);
+
+ if (mMasterKeyIds.length > 1 && mHasSecret) {
+ // secret keys can only be deleted individually
+ OperationResult.OperationLog log = new OperationResult.OperationLog();
+ log.add(OperationResult.LogType.MSG_DEL_ERROR_MULTI_SECRET, 0);
+ returnResult(new DeleteResult(OperationResult.RESULT_ERROR, log, 0,
+ mMasterKeyIds.length));
+ }
+
+ if (mMasterKeyIds.length == 1 && mHasSecret) {
+ // if mMasterKeyIds.length == 0 we let the DeleteOperation respond
+ try {
+ HashMap<String, Object> data = new ProviderHelper(this).getUnifiedData(
+ mMasterKeyIds[0], new String[]{
+ KeychainContract.KeyRings.USER_ID,
+ KeychainContract.KeyRings.IS_REVOKED
+ }, new int[]{
+ ProviderHelper.FIELD_TYPE_STRING,
+ ProviderHelper.FIELD_TYPE_INTEGER
+ }
+ );
+
+ String name;
+ KeyRing.UserId mainUserId = KeyRing.splitUserId(
+ (String) data.get(KeychainContract.KeyRings.USER_ID));
+ if (mainUserId.name != null) {
+ name = mainUserId.name;
+ } else {
+ name = getString(R.string.user_id_no_name);
+ }
+
+ if ((long) data.get(KeychainContract.KeyRings.IS_REVOKED) > 0) {
+ showNormalDeleteDialog();
+ } else {
+ showRevokeDeleteDialog(name);
+ }
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.e(Constants.TAG,
+ "Secret key to delete not found at DeleteKeyDialogActivity for "
+ + mMasterKeyIds[0], e);
+ finish();
+ }
+ } else {
+ showNormalDeleteDialog();
+ }
+ }
+
+ private void showNormalDeleteDialog() {
+
+ DeleteKeyDialogFragment deleteKeyDialogFragment
+ = DeleteKeyDialogFragment.newInstance(mMasterKeyIds, mHasSecret);
+
+ deleteKeyDialogFragment.show(getSupportFragmentManager(), "deleteKeyDialog");
+
+ }
+
+ private void showRevokeDeleteDialog(String keyname) {
+
+ RevokeDeleteDialogFragment fragment = RevokeDeleteDialogFragment.newInstance(keyname);
+ fragment.show(getSupportFragmentManager(), "deleteRevokeDialog");
+ }
+
+ private void startRevocationOperation() {
+ mRevokeOpHelper.cryptoOperation(new CryptoInputParcel(new Date(), false));
+ }
+
+ private void startDeletionOperation() {
+ mDeleteOpHelper.cryptoOperation();
+ }
+
+ private CryptoOperationHelper.Callback<RevokeKeyringParcel, RevokeResult> getRevocationCallback() {
+
+ return new CryptoOperationHelper.Callback<RevokeKeyringParcel, RevokeResult>() {
+ @Override
+ public RevokeKeyringParcel createOperationInput() {
+ return new RevokeKeyringParcel(mMasterKeyIds[0], true,
+ getIntent().getStringExtra(EXTRA_KEYSERVER));
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(RevokeResult result) {
+ returnResult(result);
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ @Override
+ public void onCryptoOperationError(RevokeResult result) {
+ returnResult(result);
+ }
+
+ @Override
+ public boolean onCryptoSetProgress(String msg, int progress, int max) {
+ return false;
+ }
+ };
+ }
+
+ private CryptoOperationHelper.Callback<DeleteKeyringParcel, DeleteResult> getDeletionCallback() {
+
+ return new CryptoOperationHelper.Callback<DeleteKeyringParcel, DeleteResult>() {
+ @Override
+ public DeleteKeyringParcel createOperationInput() {
+ return new DeleteKeyringParcel(mMasterKeyIds, mHasSecret);
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(DeleteResult result) {
+ returnResult(result);
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ @Override
+ public void onCryptoOperationError(DeleteResult result) {
+ returnResult(result);
+ }
+
+ @Override
+ public boolean onCryptoSetProgress(String msg, int progress, int max) {
+ return false;
+ }
+ };
+ }
+
+ private void returnResult(OperationResult result) {
+ Intent intent = new Intent();
+ intent.putExtra(OperationResult.EXTRA_RESULT, result);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data);
+ mRevokeOpHelper.handleActivityResult(requestCode, resultCode, data);
+ }
+
+ public static class DeleteKeyDialogFragment extends DialogFragment {
+
+ private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids";
+ private static final String ARG_HAS_SECRET = "has_secret";
+
+ private TextView mMainMessage;
+ private View mInflateView;
+
+ /**
+ * Creates new instance of this delete file dialog fragment
+ */
+ public static DeleteKeyDialogFragment newInstance(long[] masterKeyIds, boolean hasSecret) {
+ DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment();
+ Bundle args = new Bundle();
+
+ args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds);
+ args.putBoolean(ARG_HAS_SECRET, hasSecret);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final FragmentActivity activity = getActivity();
+
+ final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS);
+ final boolean hasSecret = getArguments().getBoolean(ARG_HAS_SECRET);
+
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
+
+ CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme);
+
+ // Setup custom View to display in AlertDialog
+ LayoutInflater inflater = LayoutInflater.from(theme);
+ mInflateView = inflater.inflate(R.layout.view_key_delete_fragment, null);
+ builder.setView(mInflateView);
+
+ mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage);
+
+ // If only a single key has been selected
+ if (masterKeyIds.length == 1) {
+ long masterKeyId = masterKeyIds[0];
+
+ try {
+ HashMap<String, Object> data = new ProviderHelper(activity).getUnifiedData(
+ masterKeyId, new String[]{
+ KeychainContract.KeyRings.USER_ID,
+ KeychainContract.KeyRings.HAS_ANY_SECRET
+ }, new int[]{
+ ProviderHelper.FIELD_TYPE_STRING,
+ ProviderHelper.FIELD_TYPE_INTEGER
+ }
+ );
+ String name;
+ KeyRing.UserId mainUserId = KeyRing.splitUserId((String) data.get(KeychainContract.KeyRings.USER_ID));
+ if (mainUserId.name != null) {
+ name = mainUserId.name;
+ } else {
+ name = getString(R.string.user_id_no_name);
+ }
+
+ if (hasSecret) {
+ // show title only for secret key deletions,
+ // see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior
+ builder.setTitle(getString(R.string.title_delete_secret_key, name));
+ mMainMessage.setText(getString(R.string.secret_key_deletion_confirmation, name));
+ } else {
+ mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name));
+ }
+ } catch (ProviderHelper.NotFoundException e) {
+ dismiss();
+ return null;
+ }
+ } else {
+ mMainMessage.setText(R.string.key_deletion_confirmation_multi);
+ }
+
+ builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+
+ ((DeleteKeyDialogActivity) getActivity()).startDeletionOperation();
+ }
+ });
+
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ return builder.show();
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ getActivity().setResult(RESULT_CANCELED);
+ getActivity().finish();
+ }
+ }
+
+ public static class RevokeDeleteDialogFragment extends DialogFragment {
+
+ public static final String ARG_KEY_NAME = "arg_key_name";
+
+ public static RevokeDeleteDialogFragment newInstance(String keyName) {
+ Bundle args = new Bundle();
+ args.putString(ARG_KEY_NAME, keyName);
+ RevokeDeleteDialogFragment frag = new RevokeDeleteDialogFragment();
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+
+ final String CHOICE_REVOKE = getString(R.string.del_rev_dialog_choice_rev_upload);
+ final String CHOICE_DELETE = getString(R.string.del_rev_dialog_choice_delete);
+
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
+
+ CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme);
+ builder.setTitle(getString(R.string.del_rev_dialog_title,
+ getArguments().get(ARG_KEY_NAME)));
+
+ LayoutInflater inflater = LayoutInflater.from(theme);
+ View view = inflater.inflate(R.layout.del_rev_dialog, null);
+ builder.setView(view);
+
+ final Spinner spinner = (Spinner) view.findViewById(R.id.spinner);
+
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ builder.setPositiveButton(R.string.del_rev_dialog_btn_revoke,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+
+ String choice = spinner.getSelectedItem().toString();
+ if (choice.equals(CHOICE_REVOKE)) {
+ ((DeleteKeyDialogActivity) activity)
+ .startRevocationOperation();
+ } else if (choice.equals(CHOICE_DELETE)) {
+ ((DeleteKeyDialogActivity) activity)
+ .showNormalDeleteDialog();
+ } else {
+ throw new AssertionError(
+ "Unsupported delete type in RevokeDeleteDialogFragment");
+ }
+ }
+ });
+
+ final AlertDialog alertDialog = builder.show();
+
+ spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+
+ String choice = parent.getItemAtPosition(pos).toString();
+
+ if (choice.equals(CHOICE_REVOKE)) {
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
+ .setText(R.string.del_rev_dialog_btn_revoke);
+ } else if (choice.equals(CHOICE_DELETE)) {
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
+ .setText(R.string.del_rev_dialog_btn_delete);
+ } else {
+ throw new AssertionError(
+ "Unsupported delete type in RevokeDeleteDialogFragment");
+ }
+ }
+
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ return alertDialog;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ getActivity().setResult(RESULT_CANCELED);
+ getActivity().finish();
+ }
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
index be21cdde1..3c8e972b9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
@@ -41,13 +41,7 @@ public class DisplayTextActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(Activity.RESULT_CANCELED);
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_CANCELED, false);
// Handle intent actions
handleActions(savedInstanceState, getIntent());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java
index 7b3af48cc..dc06e9115 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java
@@ -17,6 +17,10 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -29,9 +33,9 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.ShareHelper;
public class DisplayTextFragment extends DecryptFragment {
@@ -80,8 +84,19 @@ public class DisplayTextFragment extends DecryptFragment {
}
private void copyToClipboard(String text) {
- ClipboardReflection.copyToClipboard(getActivity(), text);
- Notify.create(getActivity(), R.string.text_copied_to_clipboard, Notify.Style.OK).show();
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipMan == null) {
+ Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR).show();
+ return;
+ }
+
+ clipMan.setPrimaryClip(ClipData.newPlainText(Constants.CLIPBOARD_LABEL, text));
+ Notify.create(activity, R.string.text_copied_to_clipboard, Style.OK).show();
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index 1363d44f2..4769e68d8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -57,7 +57,7 @@ import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment;
@@ -68,7 +68,9 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
-public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel, OperationResult>
+import java.util.Date;
+
+public class EditKeyFragment extends QueueingCryptoOperationFragment<SaveKeyringParcel, OperationResult>
implements LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
@@ -151,7 +153,7 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
if (mDataUri == null) {
returnKeyringParcel();
} else {
- cryptoOperation(new CryptoInputParcel());
+ cryptoOperation(new CryptoInputParcel(new Date()));
}
}
}, new OnClickListener() {
@@ -192,7 +194,7 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
private void loadData(Uri dataUri) {
mDataUri = dataUri;
- Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
+ Log.i(Constants.TAG, "mDataUri: " + mDataUri);
// load the secret key ring. we do verify here that the passphrase is correct, so cached won't do
try {
@@ -437,44 +439,50 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
}
break;
}
- case EditSubkeyDialogFragment.MESSAGE_KEYTOCARD: {
- Activity activity = EditKeyFragment.this.getActivity();
- SecretKeyType secretKeyType = mSubkeysAdapter.getSecretKeyType(position);
- if (secretKeyType == SecretKeyType.DIVERT_TO_CARD ||
- secretKeyType == SecretKeyType.GNU_DUMMY) {
- Notify.create(activity, R.string.edit_key_error_bad_nfc_stripped, Notify.Style.ERROR)
- .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
- break;
- }
- int algorithm = mSubkeysAdapter.getAlgorithm(position);
- // these are the PGP constants for RSA_GENERAL, RSA_ENCRYPT and RSA_SIGN
- if (algorithm != 1 && algorithm != 2 && algorithm != 3) {
- Notify.create(activity, R.string.edit_key_error_bad_nfc_algo, Notify.Style.ERROR)
- .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
- break;
- }
- if (mSubkeysAdapter.getKeySize(position) != 2048) {
- Notify.create(activity, R.string.edit_key_error_bad_nfc_size, Notify.Style.ERROR)
- .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
- break;
- }
-
-
- SubkeyChange change;
- change = mSaveKeyringParcel.getSubkeyChange(keyId);
- if (change == null) {
- mSaveKeyringParcel.mChangeSubKeys.add(
- new SubkeyChange(keyId, false, true)
- );
- break;
- }
- // toggle
- change.mMoveKeyToCard = !change.mMoveKeyToCard;
- if (change.mMoveKeyToCard && change.mDummyStrip) {
- // User had chosen to strip key, but now wants to divert it.
- change.mDummyStrip = false;
- }
+ case EditSubkeyDialogFragment.MESSAGE_MOVE_KEY_TO_CARD: {
+ // TODO: enable later when Admin PIN handling is resolved
+ Notify.create(getActivity(),
+ "This feature will be available in an upcoming OpenKeychain version.",
+ Notify.Style.WARN).show();
break;
+
+// Activity activity = EditKeyFragment.this.getActivity();
+// SecretKeyType secretKeyType = mSubkeysAdapter.getSecretKeyType(position);
+// if (secretKeyType == SecretKeyType.DIVERT_TO_CARD ||
+// secretKeyType == SecretKeyType.GNU_DUMMY) {
+// Notify.create(activity, R.string.edit_key_error_bad_nfc_stripped, Notify.Style.ERROR)
+// .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
+// break;
+// }
+// int algorithm = mSubkeysAdapter.getAlgorithm(position);
+// // these are the PGP constants for RSA_GENERAL, RSA_ENCRYPT and RSA_SIGN
+// if (algorithm != 1 && algorithm != 2 && algorithm != 3) {
+// Notify.create(activity, R.string.edit_key_error_bad_nfc_algo, Notify.Style.ERROR)
+// .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
+// break;
+// }
+// if (mSubkeysAdapter.getKeySize(position) != 2048) {
+// Notify.create(activity, R.string.edit_key_error_bad_nfc_size, Notify.Style.ERROR)
+// .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
+// break;
+// }
+//
+//
+// SubkeyChange change;
+// change = mSaveKeyringParcel.getSubkeyChange(keyId);
+// if (change == null) {
+// mSaveKeyringParcel.mChangeSubKeys.add(
+// new SubkeyChange(keyId, false, true)
+// );
+// break;
+// }
+// // toggle
+// change.mMoveKeyToCard = !change.mMoveKeyToCard;
+// if (change.mMoveKeyToCard && change.mDummyStrip) {
+// // User had chosen to strip key, but now wants to divert it.
+// change.mDummyStrip = false;
+// }
+// break;
}
}
getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad();
@@ -612,13 +620,16 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
}
@Override
- public void onCryptoOperationSuccess(OperationResult result) {
+ public void onQueuedOperationSuccess(OperationResult result) {
+
+ // null-protected from Queueing*Fragment
+ Activity activity = getActivity();
// if good -> finish, return result to showkey and display there!
Intent intent = new Intent();
intent.putExtra(OperationResult.EXTRA_RESULT, result);
- getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
- getActivity().finish();
+ activity.setResult(EditKeyActivity.RESULT_OK, intent);
+ activity.finish();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java
index 779b22535..fc72a6c9f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java
@@ -124,8 +124,7 @@ public class EncryptDecryptOverviewFragment extends Fragment {
super.onResume();
// get text from clipboard
- final CharSequence clipboardText =
- ClipboardReflection.getClipboardText(getActivity());
+ final CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
// if it's null, nothing to do here /o/
if (clipboardText == null) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
index d51b6e0ff..136787984 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -41,12 +42,7 @@ public class EncryptFilesActivity extends EncryptActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_OK, false);
Intent intent = getIntent();
String action = intent.getAction();
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 215af5885..3dc93872d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
@@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -35,6 +36,7 @@ import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -56,6 +58,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
@@ -276,18 +279,21 @@ public class EncryptFilesFragment
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.encrypt_save: {
+ hideKeyboard();
mAfterEncryptAction = AfterEncryptAction.SAVE;
- cryptoOperation();
+ cryptoOperation(new CryptoInputParcel(new Date()));
break;
}
case R.id.encrypt_share: {
+ hideKeyboard();
mAfterEncryptAction = AfterEncryptAction.SHARE;
- cryptoOperation();
+ cryptoOperation(new CryptoInputParcel(new Date()));
break;
}
case R.id.encrypt_copy: {
+ hideKeyboard();
mAfterEncryptAction = AfterEncryptAction.COPY;
- cryptoOperation();
+ cryptoOperation(new CryptoInputParcel(new Date()));
break;
}
case R.id.check_use_armor: {
@@ -386,7 +392,13 @@ public class EncryptFilesFragment
}
@Override
- public void onCryptoOperationSuccess(final SignEncryptResult result) {
+ public void onQueuedOperationSuccess(final SignEncryptResult result) {
+ super.onQueuedOperationSuccess(result);
+
+ hideKeyboard();
+
+ // protected by Queueing*Fragment
+ FragmentActivity activity = getActivity();
if (mDeleteAfterEncrypt) {
// TODO make behavior coherent here
@@ -400,13 +412,18 @@ public class EncryptFilesFragment
// Share encrypted message/file
startActivity(sendWithChooserExcludingEncrypt());
} else {
+ Activity activity = getActivity();
+ if (activity == null) {
+ // it's gone, there's nothing we can do here
+ return;
+ }
// Save encrypted file
- result.createNotify(getActivity()).show();
+ result.createNotify(activity).show();
}
}
});
- deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog");
+ deleteFileDialog.show(activity.getSupportFragmentManager(), "deleteDialog");
} else {
switch (mAfterEncryptAction) {
@@ -417,25 +434,24 @@ public class EncryptFilesFragment
break;
case COPY:
- Activity activity = getActivity();
- if (activity == null) {
- // it's gone, there's nothing we can do here
- return;
- }
ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipMan == null) {
+ Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR).show();
+ break;
+ }
ClipData clip = new ClipData(getString(R.string.label_clip_title),
// make available as application/pgp-encrypted
new String[] { "text/plain" },
new ClipData.Item(mOutputUris.get(0))
);
clipMan.setPrimaryClip(clip);
- result.createNotify(getActivity()).show();
+ result.createNotify(activity).show();
break;
case SAVE:
// Encrypted file was saved already, just show notification
- result.createNotify(getActivity()).show();
+ result.createNotify(activity).show();
break;
}
}
@@ -652,7 +668,7 @@ public class EncryptFilesFragment
mOutputUris.add(data.getData());
// make sure this is correct at this point
mAfterEncryptAction = AfterEncryptAction.SAVE;
- cryptoOperation();
+ cryptoOperation(new CryptoInputParcel(new Date()));
}
return;
}
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 cb26ea452..a849cdf12 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
@@ -39,12 +40,7 @@ public class EncryptTextActivity extends EncryptActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_OK, false);
Intent intent = getIntent();
String action = intent.getAction();
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 886c52651..32257eba5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
@@ -18,6 +18,9 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
@@ -33,11 +36,11 @@ import android.widget.TextView;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
@@ -46,6 +49,7 @@ import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.ShareHelper;
+import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@@ -164,13 +168,15 @@ public class EncryptTextFragment
// break;
// }
case R.id.encrypt_copy: {
+ hideKeyboard();
mShareAfterEncrypt = false;
- cryptoOperation();
+ cryptoOperation(new CryptoInputParcel(new Date()));
break;
}
case R.id.encrypt_share: {
+ hideKeyboard();
mShareAfterEncrypt = true;
- cryptoOperation();
+ cryptoOperation(new CryptoInputParcel(new Date()));
break;
}
default: {
@@ -265,8 +271,21 @@ public class EncryptTextFragment
return data;
}
- private void copyToClipboard(byte[] resultBytes) {
- ClipboardReflection.copyToClipboard(getActivity(), new String(resultBytes));
+ private void copyToClipboard(SignEncryptResult result) {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipMan == null) {
+ Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR).show();
+ return;
+ }
+
+ ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, new String(result.getResultBytes()));
+ clipMan.setPrimaryClip(clip);
+ result.createNotify(activity).show();
}
/**
@@ -316,18 +335,17 @@ public class EncryptTextFragment
}
@Override
- public void onCryptoOperationSuccess(SignEncryptResult result) {
+ public void onQueuedOperationSuccess(SignEncryptResult result) {
+ super.onQueuedOperationSuccess(result);
+
+ hideKeyboard();
if (mShareAfterEncrypt) {
// Share encrypted message/file
startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes()));
} else {
// Copy to clipboard
- copyToClipboard(result.getResultBytes());
- result.createNotify(getActivity()).show();
- // Notify.create(EncryptTextActivity.this,
- // R.string.encrypt_sign_clipboard_successful, Notify.Style.OK)
- // .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment));
+ copyToClipboard(result);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
index ac4b94d64..acbb695df 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2012-2015 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
@@ -51,7 +51,7 @@ public class HelpAboutFragment extends Fragment {
try {
String html = new Markdown4jProcessor().process(
getActivity().getResources().openRawResource(R.raw.help_about));
- aboutTextView.setHtmlFromString(html, true);
+ aboutTextView.setHtmlFromString(html, new HtmlTextView.LocalImageGetter());
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpMarkdownFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpMarkdownFragment.java
index 97d39feb1..73ce7e03e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpMarkdownFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpMarkdownFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2012-2015 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
@@ -17,7 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.TypedValue;
@@ -34,9 +33,6 @@ import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
public class HelpMarkdownFragment extends Fragment {
- private Activity mActivity;
-
- private int mHtmlFile;
public static final String ARG_MARKDOWN_RES = "htmlFile";
@@ -56,15 +52,13 @@ public class HelpMarkdownFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- mActivity = getActivity();
-
- mHtmlFile = getArguments().getInt(ARG_MARKDOWN_RES);
+ int mHtmlFile = getArguments().getInt(ARG_MARKDOWN_RES);
- ScrollView scroller = new ScrollView(mActivity);
- HtmlTextView text = new HtmlTextView(mActivity);
+ ScrollView scroller = new ScrollView(getActivity());
+ HtmlTextView text = new HtmlTextView(getActivity());
// padding
- int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, mActivity
+ int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getActivity()
.getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, 0);
@@ -72,8 +66,9 @@ public class HelpMarkdownFragment extends Fragment {
// load markdown from raw resource
try {
- String html = new Markdown4jProcessor().process(getActivity().getResources().openRawResource(mHtmlFile));
- text.setHtmlFromString(html, true);
+ String html = new Markdown4jProcessor().process(
+ getActivity().getResources().openRawResource(mHtmlFile));
+ text.setHtmlFromString(html, new HtmlTextView.LocalImageGetter());
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
}
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 ba4f759e6..4ef6c40dc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -92,6 +93,7 @@ public class ImportKeysActivity extends BaseNfcActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setFullScreenDialogClose(Activity.RESULT_CANCELED, true);
mImportButton = findViewById(R.id.import_import);
mImportButton.setOnClickListener(new OnClickListener() {
@Override
@@ -224,9 +226,9 @@ public class ImportKeysActivity extends BaseNfcActivity
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
+ // we don't set the keyserver for ImportKeysListFragment since
+ // it'll be set in the cloudSearchPrefs of ImportKeysCloudFragment
+ // which is used when the user clicks on the search button
startListFragment(savedInstanceState, null, null, null, null);
} else {
// we allow our users to edit the query if they wish
@@ -316,7 +318,8 @@ public class ImportKeysActivity extends BaseNfcActivity
* specified in user preferences
*/
- private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit, String keyserver) {
+ 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.
@@ -346,7 +349,7 @@ public class ImportKeysActivity extends BaseNfcActivity
}
}
- public void loadCallback(ImportKeysListFragment.LoaderState loaderState) {
+ public void loadCallback(final ImportKeysListFragment.LoaderState loaderState) {
mListFragment.loadNew(loaderState);
}
@@ -395,7 +398,7 @@ public class ImportKeysActivity extends BaseNfcActivity
}
mOperationHelper = new CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult>(
- this, this, R.string.progress_importing
+ 1, this, this, R.string.progress_importing
);
ImportKeysListFragment.LoaderState ls = mListFragment.getLoaderState();
@@ -448,10 +451,8 @@ public class ImportKeysActivity extends BaseNfcActivity
}
@Override
- protected void onNfcPerform() throws IOException {
- // this displays the key or moves to the yubikey import dialogue.
- super.onNfcPerform();
- // either way, finish afterwards
+ protected void onNfcPostExecute() throws IOException {
+ // either way, finish after NFC AsyncTask
finish();
}
@@ -463,7 +464,7 @@ public class ImportKeysActivity extends BaseNfcActivity
}
}
- public void handleResult (ImportKeyResult result) {
+ public void handleResult(ImportKeyResult result) {
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())
|| ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
Intent intent = new Intent();
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 bf7e41045..53e5efabe 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
@@ -34,6 +35,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.GetKeyResult;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListCloudLoader;
@@ -41,7 +43,9 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
@@ -62,6 +66,7 @@ public class ImportKeysListFragment extends ListFragment implements
private Activity mActivity;
private ImportKeysAdapter mAdapter;
+ private ParcelableProxy mParcelableProxy;
private LoaderState mLoaderState;
@@ -71,6 +76,8 @@ public class ImportKeysListFragment extends ListFragment implements
private LongSparseArray<ParcelableKeyRing> mCachedKeyData;
private boolean mNonInteractive;
+ private boolean mShowingOrbotDialog;
+
public LoaderState getLoaderState() {
return mLoaderState;
}
@@ -126,6 +133,7 @@ public class ImportKeysListFragment extends ListFragment implements
/**
* 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
+ * Will immediately load data if non-null bytes/dataUri/serverQuery
*
* @param bytes byte data containing list of keyrings to be imported
* @param dataUri file from which keyrings are to be imported
@@ -141,7 +149,7 @@ public class ImportKeysListFragment extends ListFragment implements
/**
* 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
+ * Will immediately load data if non-null bytes/dataUri/serverQuery is supplied
*
* @param bytes byte data containing list of keyrings to be imported
* @param dataUri file from which keyrings are to be imported
@@ -259,6 +267,7 @@ public class ImportKeysListFragment extends ListFragment implements
}
public void loadNew(LoaderState loaderState) {
+
mLoaderState = loaderState;
restartLoaders();
@@ -301,7 +310,8 @@ public class ImportKeysListFragment extends ListFragment implements
}
case LOADER_ID_CLOUD: {
CloudLoaderState ls = (CloudLoaderState) mLoaderState;
- return new ImportKeysListCloudLoader(getActivity(), ls.mServerQuery, ls.mCloudPrefs);
+ return new ImportKeysListCloudLoader(getActivity(), ls.mServerQuery, ls.mCloudPrefs,
+ mParcelableProxy);
}
default:
@@ -349,6 +359,46 @@ public class ImportKeysListFragment extends ListFragment implements
if (getKeyResult.success()) {
// No error
+ } else if (getKeyResult.isPending()) {
+ if (getKeyResult.getRequiredInputParcel().mType ==
+ RequiredInputParcel.RequiredInputType.ENABLE_ORBOT) {
+ if (mShowingOrbotDialog) {
+ // to prevent dialogs stacking
+ return;
+ }
+
+ // this is because we can't commit fragment dialogs in onLoadFinished
+ Runnable showOrbotDialog = new Runnable() {
+ @Override
+ public void run() {
+ final Runnable ignoreTor = new Runnable() {
+ @Override
+ public void run() {
+ mParcelableProxy = ParcelableProxy
+ .getForNoProxy();
+ mShowingOrbotDialog = false;
+ restartLoaders();
+ }
+ };
+
+ final Runnable dialogDismiss = new Runnable() {
+ @Override
+ public void run() {
+ mShowingOrbotDialog = false;
+ }
+ };
+
+ if (OrbotHelper.putOrbotInRequiredState(
+ ignoreTor, dialogDismiss, getActivity())) {
+ // looks like we didn't have to show the
+ // dialog after all
+ restartLoaders();
+ }
+ }
+ };
+ new Handler().post(showOrbotDialog );
+ mShowingOrbotDialog = true;
+ }
} else {
getKeyResult.createNotify(getActivity()).show();
}
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 da713d0d8..b60f3984c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
@@ -110,7 +110,16 @@ public class ImportKeysProxyActivity extends FragmentActivity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mImportOpHelper != null) {
- mImportOpHelper.cryptoOperation();
+ if (!mImportOpHelper.handleActivityResult(requestCode, resultCode, data)) {
+ // if a result has been returned, and it does not belong to mImportOpHelper,
+ // return it down to other activity
+ if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ returnResult(data);
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ finish();
+ }
+ }
}
if (requestCode == IntentIntegratorSupportV4.REQUEST_CODE) {
@@ -128,13 +137,6 @@ public class ImportKeysProxyActivity extends FragmentActivity
return;
}
- // if a result has been returned, return it down to other activity
- if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
- returnResult(data);
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- finish();
- }
}
private void processScannedContent(String content) {
@@ -157,8 +159,7 @@ public class ImportKeysProxyActivity extends FragmentActivity
returnResult(intent);
return;
}
-
- String fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH);
+ final String fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH);
if (!fingerprint.matches("[a-fA-F0-9]{40}")) {
SingletonResult result = new SingletonResult(
SingletonResult.RESULT_ERROR, LogType.MSG_WRONG_QR_CODE_FP);
@@ -222,7 +223,7 @@ public class ImportKeysProxyActivity extends FragmentActivity
mKeyList = keyRings;
- mImportOpHelper = new CryptoOperationHelper<>(this, this, R.string.progress_importing);
+ mImportOpHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_importing);
mImportOpHelper.cryptoOperation();
}
@@ -256,7 +257,6 @@ public class ImportKeysProxyActivity extends FragmentActivity
Intent data = new Intent();
data.putExtras(returnData);
returnResult(data);
- return;
}
@Override
@@ -273,7 +273,8 @@ public class ImportKeysProxyActivity extends FragmentActivity
// only one message sent during the beam
NdefMessage msg = (NdefMessage) rawMsgs[0];
// record 0 contains the MIME type, record 1 is the AAR, if present
- byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload();
+ final byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload();
+
importKeys(receivedKeyringBytes);
}
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 e038cf948..0488d8235 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -18,6 +18,11 @@
package org.sufficientlysecure.keychain.ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.app.Activity;
@@ -28,9 +33,6 @@ import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@@ -51,12 +53,10 @@ import android.widget.TextView;
import com.getbase.floatingactionbutton.FloatingActionButton;
import com.getbase.floatingactionbutton.FloatingActionsMenu;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
-import org.sufficientlysecure.keychain.operations.results.DeleteResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.provider.KeychainContract;
@@ -65,22 +65,15 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ConsolidateInputParcel;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
-import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
-import org.sufficientlysecure.keychain.util.ExportHelper;
import org.sufficientlysecure.keychain.util.FabContainer;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Preferences;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
@@ -93,10 +86,9 @@ public class KeyListFragment extends LoaderFragment
LoaderManager.LoaderCallbacks<Cursor>, FabContainer,
CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
- static final int REQUEST_REPEAT_PASSPHRASE = 1;
- static final int REQUEST_ACTION = 2;
-
- ExportHelper mExportHelper;
+ static final int REQUEST_ACTION = 1;
+ private static final int REQUEST_DELETE = 2;
+ private static final int REQUEST_VIEW_KEY = 3;
private KeyListAdapter mAdapter;
private StickyListHeadersListView mStickyList;
@@ -116,18 +108,6 @@ public class KeyListFragment extends LoaderFragment
// for ConsolidateOperation
private CryptoOperationHelper<ConsolidateInputParcel, ConsolidateResult> mConsolidateOpHelper;
- // This ids for multiple key export.
- private ArrayList<Long> mIdsForRepeatAskPassphrase;
- // This index for remembering the number of master key.
- private int mIndex;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mExportHelper = new ExportHelper(getActivity());
- }
-
/**
* Load custom layout with StickyListView from library
*/
@@ -238,19 +218,7 @@ public class KeyListFragment extends LoaderFragment
}
case R.id.menu_key_list_multi_delete: {
ids = mAdapter.getCurrentSelectedMasterKeyIds();
- showDeleteKeyDialog(mode, ids, mAdapter.isAnySecretSelected());
- break;
- }
- case R.id.menu_key_list_multi_export: {
- ids = mAdapter.getCurrentSelectedMasterKeyIds();
- showMultiExportDialog(ids);
- break;
- }
- case R.id.menu_key_list_multi_select_all: {
- // select all
- for (int i = 0; i < mAdapter.getCount(); i++) {
- mStickyList.setItemChecked(i, true);
- }
+ showDeleteKeyDialog(ids, mAdapter.isAnySecretSelected());
break;
}
}
@@ -366,7 +334,7 @@ public class KeyListFragment extends LoaderFragment
Intent viewIntent = new Intent(getActivity(), ViewKeyActivity.class);
viewIntent.setData(
KeyRings.buildGenericKeyRingUri(mAdapter.getMasterKeyId(position)));
- startActivity(viewIntent);
+ startActivityForResult(viewIntent, REQUEST_VIEW_KEY);
}
protected void encrypt(ActionMode mode, long[] masterKeyIds) {
@@ -384,38 +352,15 @@ public class KeyListFragment extends LoaderFragment
*
* @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not
*/
- public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) {
- // Can only work on singular secret keys
- if (hasSecret && masterKeyIds.length > 1) {
- Notify.create(getActivity(), R.string.secret_cannot_multiple,
- Notify.Style.ERROR).show();
- return;
+ public void showDeleteKeyDialog(long[] masterKeyIds, boolean hasSecret) {
+ Intent intent = new Intent(getActivity(), DeleteKeyDialogActivity.class);
+ intent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, masterKeyIds);
+ intent.putExtra(DeleteKeyDialogActivity.EXTRA_HAS_SECRET, hasSecret);
+ if (hasSecret) {
+ intent.putExtra(DeleteKeyDialogActivity.EXTRA_KEYSERVER,
+ Preferences.getPreferences(getActivity()).getPreferredKeyserver());
}
-
- // Message is received after key is deleted
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.arg1 == DeleteKeyDialogFragment.MESSAGE_OKAY) {
- Bundle data = message.getData();
- if (data != null) {
- DeleteResult result = data.getParcelable(DeleteResult.EXTRA_RESULT);
- if (result != null) {
- result.createNotify(getActivity()).show();
- }
- }
- mode.finish();
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
- masterKeyIds);
-
- deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
+ startActivityForResult(intent, REQUEST_DELETE);
}
@@ -470,18 +415,10 @@ public class KeyListFragment extends LoaderFragment
createKey();
return true;
- case R.id.menu_key_list_export:
- mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
- return true;
-
case R.id.menu_key_list_update_all_keys:
updateAllKeys();
return true;
- case R.id.menu_key_list_debug_cons:
- consolidate();
- return true;
-
case R.id.menu_key_list_debug_read:
try {
KeychainDatabase.debugBackup(getActivity(), true);
@@ -512,6 +449,10 @@ public class KeyListFragment extends LoaderFragment
getActivity().finish();
return true;
+ case R.id.menu_key_list_debug_cons:
+ consolidate();
+ return true;
+
default:
return super.onOptionsItemSelected(item);
}
@@ -602,7 +543,7 @@ public class KeyListFragment extends LoaderFragment
mKeyserver = cloudPrefs.keyserver;
}
- mImportOpHelper = new CryptoOperationHelper<>(this,
+ mImportOpHelper = new CryptoOperationHelper<>(1, this,
this, R.string.progress_updating);
mImportOpHelper.cryptoOperation();
}
@@ -639,45 +580,11 @@ public class KeyListFragment extends LoaderFragment
};
mConsolidateOpHelper =
- new CryptoOperationHelper<>(this, callback, R.string.progress_importing);
+ new CryptoOperationHelper<>(2, this, callback, R.string.progress_importing);
mConsolidateOpHelper.cryptoOperation();
}
- private void showMultiExportDialog(long[] masterKeyIds) {
- mIdsForRepeatAskPassphrase = new ArrayList<>();
- for (long id : masterKeyIds) {
- try {
- if (PassphraseCacheService.getCachedPassphrase(
- getActivity(), id, id) == null) {
- mIdsForRepeatAskPassphrase.add(id);
- }
- } catch (PassphraseCacheService.KeyNotFoundException e) {
- // This happens when the master key is stripped
- // and ignore this key.
- }
- }
- mIndex = 0;
- if (mIdsForRepeatAskPassphrase.size() != 0) {
- startPassphraseActivity();
- return;
- }
- long[] idsForMultiExport = new long[mIdsForRepeatAskPassphrase.size()];
- for (int i = 0; i < mIdsForRepeatAskPassphrase.size(); ++i) {
- idsForMultiExport[i] = mIdsForRepeatAskPassphrase.get(i);
- }
- mExportHelper.showExportKeysDialog(idsForMultiExport,
- Constants.Path.APP_DIR_FILE,
- mAdapter.isAnySecretSelected());
- }
-
- private void startPassphraseActivity() {
- Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
- long masterKeyId = mIdsForRepeatAskPassphrase.get(mIndex++);
- intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, masterKeyId);
- startActivityForResult(intent, REQUEST_REPEAT_PASSPHRASE);
- }
-
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mImportOpHelper != null) {
@@ -688,31 +595,37 @@ public class KeyListFragment extends LoaderFragment
mConsolidateOpHelper.handleActivityResult(requestCode, resultCode, data);
}
- if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
- if (resultCode != Activity.RESULT_OK) {
- return;
- }
- if (mIndex < mIdsForRepeatAskPassphrase.size()) {
- startPassphraseActivity();
- return;
- }
- long[] idsForMultiExport = new long[mIdsForRepeatAskPassphrase.size()];
- for (int i = 0; i < mIdsForRepeatAskPassphrase.size(); ++i) {
- idsForMultiExport[i] = mIdsForRepeatAskPassphrase.get(i);
- }
- mExportHelper.showExportKeysDialog(idsForMultiExport,
- Constants.Path.APP_DIR_FILE,
- mAdapter.isAnySecretSelected());
- }
+ switch (requestCode) {
+ case REQUEST_DELETE:
+ if (mActionMode != null) {
+ mActionMode.finish();
+ }
+ if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(getActivity()).show();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ break;
- if (requestCode == REQUEST_ACTION) {
- // if a result has been returned, display a notify
- if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
- OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
- result.createNotify(getActivity()).show();
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
+ case REQUEST_ACTION:
+ // if a result has been returned, display a notify
+ if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(getActivity()).show();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ break;
+
+ case REQUEST_VIEW_KEY:
+ if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(getActivity()).show();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ break;
}
}
@@ -763,8 +676,11 @@ public class KeyListFragment extends LoaderFragment
private HashMap<Integer, Boolean> mSelection = new HashMap<>();
+ private Context mContext;
+
public KeyListAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
+ mContext = context;
}
@Override
@@ -793,9 +709,11 @@ public class KeyListFragment extends LoaderFragment
// let the adapter handle setting up the row views
View v = super.getView(position, convertView, parent);
+ int colorEmphasis = FormattingUtils.getColorFromAttr(mContext, R.attr.colorEmphasis);
+
if (mSelection.get(position) != null) {
// selected position color
- v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
+ v.setBackgroundColor(colorEmphasis);
} else {
// default color
v.setBackgroundColor(Color.TRANSPARENT);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
index 3c8fbf8c9..1cd1a3099 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
@@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogLevel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.SubLogEntryParcel;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
@@ -57,10 +58,12 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
OperationResult mResult;
public static final String EXTRA_RESULT = "log";
+ protected int mTextColor;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mTextColor = FormattingUtils.getColorFromAttr(getActivity(), R.attr.colorText);
setHasOptionsMenu(true);
}
@@ -357,13 +360,13 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
ih.mSecondText.setText(getResources().getString(subEntry.mType.getMsgId(),
subEntry.mParameters));
}
- ih.mSecondText.setTextColor(subEntry.mType.mLevel == LogLevel.DEBUG ? Color.GRAY : Color.BLACK);
+ ih.mSecondText.setTextColor(subEntry.mType.mLevel == LogLevel.DEBUG ? Color.GRAY : mTextColor);
switch (subEntry.mType.mLevel) {
case DEBUG: ih.mSecondImg.setBackgroundColor(Color.GRAY); break;
- case INFO: ih.mSecondImg.setBackgroundColor(Color.BLACK); break;
+ case INFO: ih.mSecondImg.setBackgroundColor(mTextColor); break;
case WARN: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_orange_light)); break;
case ERROR: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
- case START: ih.mSecondImg.setBackgroundColor(Color.BLACK); break;
+ case START: ih.mSecondImg.setBackgroundColor(mTextColor); break;
case OK: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_green_light)); break;
case CANCELLED: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
}
@@ -388,13 +391,13 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
entry.mParameters));
}
convertView.setPadding((entry.mIndent) * dipFactor, 0, 0, 0);
- ih.mText.setTextColor(entry.mType.mLevel == LogLevel.DEBUG ? Color.GRAY : Color.BLACK);
+ ih.mText.setTextColor(entry.mType.mLevel == LogLevel.DEBUG ? Color.GRAY : mTextColor);
switch (entry.mType.mLevel) {
case DEBUG: ih.mImg.setBackgroundColor(Color.GRAY); break;
- case INFO: ih.mImg.setBackgroundColor(Color.BLACK); break;
+ case INFO: ih.mImg.setBackgroundColor(mTextColor); break;
case WARN: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_orange_light)); break;
case ERROR: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
- case START: ih.mImg.setBackgroundColor(Color.BLACK); break;
+ case START: ih.mImg.setBackgroundColor(mTextColor); break;
case OK: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_green_light)); break;
case CANCELLED: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
}
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 ec6fd1bbe..6f5d98afd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
@@ -33,6 +33,7 @@ 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.DrawerBuilder;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
@@ -48,14 +49,15 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
static final int ID_KEYS = 1;
static final int ID_ENCRYPT_DECRYPT = 2;
static final int ID_APPS = 3;
- static final int ID_SETTINGS = 4;
- static final int ID_HELP = 5;
+ static final int ID_BACKUP = 4;
+ static final int ID_SETTINGS = 5;
+ static final int ID_HELP = 6;
// both of these are used for instrumentation testing only
public static final String EXTRA_SKIP_FIRST_TIME = "skip_first_time";
public static final String EXTRA_INIT_FRAG = "init_frag";
- public Drawer.Result mDrawerResult;
+ public Drawer mDrawer;
private Toolbar mToolbar;
@Override
@@ -67,7 +69,7 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
mToolbar.setTitle(R.string.app_name);
setSupportActionBar(mToolbar);
- mDrawerResult = new Drawer()
+ mDrawer = new DrawerBuilder()
.withActivity(this)
.withHeader(R.layout.main_drawer_header)
.withToolbar(mToolbar)
@@ -77,7 +79,9 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock)
.withIdentifier(ID_ENCRYPT_DECRYPT).withCheckable(false),
new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps)
- .withIdentifier(ID_APPS).withCheckable(false)
+ .withIdentifier(ID_APPS).withCheckable(false),
+ new PrimaryDrawerItem().withName(R.string.nav_backup).withIcon(CommunityMaterial.Icon.cmd_backup_restore)
+ .withIdentifier(ID_BACKUP).withCheckable(false)
)
.addStickyDrawerItems(
// display and stick on bottom of drawer
@@ -86,7 +90,7 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
)
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
@Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id, IDrawerItem drawerItem) {
+ public boolean onItemClick(AdapterView<?> parent, View view, int position, long id, IDrawerItem drawerItem) {
if (drawerItem != null) {
Intent intent = null;
switch(drawerItem.getIdentifier()) {
@@ -99,6 +103,9 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
case ID_APPS:
onAppsSelected();
break;
+ case ID_BACKUP:
+ onBackupSelected();
+ break;
case ID_SETTINGS:
intent = new Intent(MainActivity.this, SettingsActivity.class);
break;
@@ -110,6 +117,8 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
MainActivity.this.startActivity(intent);
}
}
+
+ return false;
}
})
.withSelectedItem(-1)
@@ -128,6 +137,11 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
getSupportFragmentManager().addOnBackStackChangedListener(this);
+ // all further initialization steps are saved as instance state
+ if (savedInstanceState != null) {
+ return;
+ }
+
Intent data = getIntent();
// If we got an EXTRA_RESULT in the intent, show the notification
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
@@ -135,20 +149,18 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
result.createNotify(this).show();
}
- if (savedInstanceState == null) {
- // always initialize keys fragment to the bottom of the backstack
- onKeysSelected();
-
- if (data != null && data.hasExtra(EXTRA_INIT_FRAG)) {
- // initialize FragmentLayout with KeyListFragment at first
- switch (data.getIntExtra(EXTRA_INIT_FRAG, -1)) {
- case ID_ENCRYPT_DECRYPT:
- onEnDecryptSelected();
- break;
- case ID_APPS:
- onAppsSelected();
- break;
- }
+ // always initialize keys fragment to the bottom of the backstack
+ onKeysSelected();
+
+ if (data != null && data.hasExtra(EXTRA_INIT_FRAG)) {
+ // initialize FragmentLayout with KeyListFragment at first
+ switch (data.getIntExtra(EXTRA_INIT_FRAG, -1)) {
+ case ID_ENCRYPT_DECRYPT:
+ onEnDecryptSelected();
+ break;
+ case ID_APPS:
+ onAppsSelected();
+ break;
}
}
@@ -170,37 +182,44 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
private void onKeysSelected() {
mToolbar.setTitle(R.string.app_name);
- mDrawerResult.setSelectionByIdentifier(ID_KEYS, false);
+ mDrawer.setSelectionByIdentifier(ID_KEYS, false);
Fragment frag = new KeyListFragment();
setFragment(frag, false);
}
private void onEnDecryptSelected() {
mToolbar.setTitle(R.string.nav_encrypt_decrypt);
- mDrawerResult.setSelectionByIdentifier(ID_ENCRYPT_DECRYPT, false);
+ mDrawer.setSelectionByIdentifier(ID_ENCRYPT_DECRYPT, false);
Fragment frag = new EncryptDecryptOverviewFragment();
setFragment(frag, true);
}
private void onAppsSelected() {
mToolbar.setTitle(R.string.nav_apps);
- mDrawerResult.setSelectionByIdentifier(ID_APPS, false);
+ mDrawer.setSelectionByIdentifier(ID_APPS, false);
Fragment frag = new AppsListFragment();
setFragment(frag, true);
}
+ private void onBackupSelected() {
+ mToolbar.setTitle(R.string.nav_backup);
+ mDrawer.setSelectionByIdentifier(ID_APPS, false);
+ Fragment frag = new BackupFragment();
+ setFragment(frag, true);
+ }
+
@Override
protected void onSaveInstanceState(Bundle outState) {
// add the values which need to be saved from the drawer to the bundle
- outState = mDrawerResult.saveInstanceState(outState);
+ outState = mDrawer.saveInstanceState(outState);
super.onSaveInstanceState(outState);
}
@Override
public void onBackPressed() {
// close the drawer first and if the drawer is closed do regular backstack handling
- if (mDrawerResult != null && mDrawerResult.isDrawerOpen()) {
- mDrawerResult.closeDrawer();
+ if (mDrawer != null && mDrawer.isDrawerOpen()) {
+ mDrawer.closeDrawer();
} else {
super.onBackPressed();
}
@@ -238,11 +257,17 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
// make sure the selected icon is the one shown at this point
if (frag instanceof KeyListFragment) {
- mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_KEYS), false);
+ mToolbar.setTitle(R.string.app_name);
+ mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_KEYS), false);
} else if (frag instanceof EncryptDecryptOverviewFragment) {
- mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_ENCRYPT_DECRYPT), false);
+ mToolbar.setTitle(R.string.nav_encrypt_decrypt);
+ mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_ENCRYPT_DECRYPT), false);
} else if (frag instanceof AppsListFragment) {
- mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_APPS), false);
+ mToolbar.setTitle(R.string.nav_apps);
+ mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_APPS), false);
+ } else if (frag instanceof BackupFragment) {
+ mToolbar.setTitle(R.string.nav_backup);
+ mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_BACKUP), false);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
index addfb6a23..1584b87ae 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
@@ -7,8 +7,13 @@
package org.sufficientlysecure.keychain.ui;
import android.content.Intent;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.view.View;
import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -28,27 +33,37 @@ import org.sufficientlysecure.keychain.util.Preferences;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
+import java.util.Date;
/**
* This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant
* NFC devices.
* <p/>
* For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf
+ * NOTE: If no CryptoInputParcel is passed via EXTRA_CRYPTO_INPUT, the CryptoInputParcel is created
+ * internally and is NOT meant to be used by signing operations before adding signature time
*/
public class NfcOperationActivity extends BaseNfcActivity {
public static final String EXTRA_REQUIRED_INPUT = "required_input";
+ public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
// passthrough for OpenPgpService
public static final String EXTRA_SERVICE_INTENT = "data";
- public static final String RESULT_DATA = "result_data";
+ public static final String RESULT_CRYPTO_INPUT = "result_data";
+
+ public ViewAnimator vAnimator;
+ public TextView vErrorText;
+ public Button vErrorTryAgainButton;
private RequiredInputParcel mRequiredInput;
private Intent mServiceIntent;
private static final byte[] BLANK_FINGERPRINT = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ private CryptoInputParcel mInputParcel;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -56,6 +71,34 @@ public class NfcOperationActivity extends BaseNfcActivity {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ mInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT);
+
+ if (mInputParcel == null) {
+ // for compatibility when used from OpenPgpService
+ // (or any place other than CryptoOperationHelper)
+ // NOTE: This CryptoInputParcel cannot be used for signing without adding signature time
+ mInputParcel = new CryptoInputParcel();
+ }
+
+ setTitle(R.string.nfc_text);
+
+ vAnimator = (ViewAnimator) findViewById(R.id.view_animator);
+ vAnimator.setDisplayedChild(0);
+ vErrorText = (TextView) findViewById(R.id.nfc_activity_3_error_text);
+ vErrorTryAgainButton = (Button) findViewById(R.id.nfc_activity_3_error_try_again);
+ vErrorTryAgainButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ resumeTagHandling();
+
+ // obtain passphrase for this subkey
+ if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_MOVE_KEY_TO_CARD) {
+ obtainYubiKeyPin(mRequiredInput);
+ }
+ vAnimator.setDisplayedChild(0);
+ }
+ });
+
Intent intent = getIntent();
Bundle data = intent.getExtras();
@@ -70,33 +113,44 @@ public class NfcOperationActivity extends BaseNfcActivity {
@Override
protected void initLayout() {
- setContentView(R.layout.nfc_activity);
+ setContentView(R.layout.nfc_operation_activity);
}
@Override
- protected void onNfcPerform() throws IOException {
+ public void onNfcPreExecute() {
+ // start with indeterminate progress
+ vAnimator.setDisplayedChild(1);
+ }
- CryptoInputParcel inputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime);
+ @Override
+ protected void doNfcInBackground() throws IOException {
switch (mRequiredInput.mType) {
case NFC_DECRYPT: {
- for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) {
- byte[] hash = mRequiredInput.mInputHashes[i];
- byte[] decryptedSessionKey = nfcDecryptSessionKey(hash);
- inputParcel.addCryptoData(hash, decryptedSessionKey);
+ for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
+ byte[] encryptedSessionKey = mRequiredInput.mInputData[i];
+ byte[] decryptedSessionKey = nfcDecryptSessionKey(encryptedSessionKey);
+ mInputParcel.addCryptoData(encryptedSessionKey, decryptedSessionKey);
}
break;
}
case NFC_SIGN: {
- for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) {
- byte[] hash = mRequiredInput.mInputHashes[i];
+ if (mInputParcel.getSignatureTime() == null) {
+ mInputParcel.addSignatureTime(new Date());
+ }
+ for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
+ byte[] hash = mRequiredInput.mInputData[i];
int algo = mRequiredInput.mSignAlgos[i];
byte[] signedHash = nfcCalculateSignature(hash, algo);
- inputParcel.addCryptoData(hash, signedHash);
+ mInputParcel.addCryptoData(hash, signedHash);
}
break;
}
case NFC_MOVE_KEY_TO_CARD: {
+ // TODO: assume PIN and Admin PIN to be default for this operation
+ mPin = new Passphrase("123456");
+ mAdminPin = new Passphrase("12345678");
+
ProviderHelper providerHelper = new ProviderHelper(this);
CanonicalizedSecretKeyRing secretKeyRing;
try {
@@ -107,8 +161,11 @@ public class NfcOperationActivity extends BaseNfcActivity {
throw new IOException("Couldn't find subkey for key to card operation.");
}
- for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) {
- byte[] subkeyBytes = mRequiredInput.mInputHashes[i];
+ byte[] newPin = mRequiredInput.mInputData[0];
+ byte[] newAdminPin = mRequiredInput.mInputData[1];
+
+ for (int i = 2; i < mRequiredInput.mInputData.length; i++) {
+ byte[] subkeyBytes = mRequiredInput.mInputData[i];
ByteBuffer buf = ByteBuffer.wrap(subkeyBytes);
long subkeyId = buf.getLong();
@@ -155,21 +212,71 @@ public class NfcOperationActivity extends BaseNfcActivity {
throw new IOException("Inappropriate key flags for smart card key.");
}
- inputParcel.addCryptoData(subkeyBytes, cardSerialNumber);
+ // TODO: Is this really needed?
+ mInputParcel.addCryptoData(subkeyBytes, cardSerialNumber);
}
+
+ // change PINs afterwards
+ nfcModifyPIN(0x81, newPin);
+ nfcModifyPIN(0x83, newAdminPin);
+
+ break;
+ }
+ default: {
+ throw new AssertionError("Unhandled mRequiredInput.mType");
}
}
+ }
+
+ @Override
+ protected void onNfcPostExecute() throws IOException {
if (mServiceIntent != null) {
- CryptoInputParcelCacheService.addCryptoInputParcel(this, mServiceIntent, inputParcel);
+ // if we're triggered by OpenPgpService
+ CryptoInputParcelCacheService.addCryptoInputParcel(this, mServiceIntent, mInputParcel);
+ mServiceIntent.putExtra(EXTRA_CRYPTO_INPUT,
+ getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT));
setResult(RESULT_OK, mServiceIntent);
} else {
Intent result = new Intent();
- result.putExtra(NfcOperationActivity.RESULT_DATA, inputParcel);
+ result.putExtra(RESULT_CRYPTO_INPUT, mInputParcel);
+ // send back the CryptoInputParcel we receive, to conform with the pattern in
+ // CryptoOperationHelper
setResult(RESULT_OK, result);
}
- finish();
+ // show finish
+ vAnimator.setDisplayedChild(2);
+
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ // check all 200ms if YubiKey has been taken away
+ while (true) {
+ if (isNfcConnected()) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ignored) {
+ }
+ } else {
+ return null;
+ }
+ }
+ }
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ finish();
+ }
+ }.execute();
+ }
+
+ @Override
+ protected void onNfcError(String error) {
+ pauseTagHandling();
+
+ vErrorText.setText(error + "\n\n" + getString(R.string.nfc_try_again_text));
+ vAnimator.setDisplayedChild(3);
}
private boolean shouldPutKey(byte[] fingerprint, int idx) throws IOException {
@@ -199,8 +306,6 @@ public class NfcOperationActivity extends BaseNfcActivity {
// clear (invalid) passphrase
PassphraseCacheService.clearCachedPassphrase(
this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId());
-
- obtainYubiKeyPin(mRequiredInput);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java
new file mode 100644
index 000000000..587044659
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@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
+ * 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;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
+import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
+
+/**
+ * Simply encapsulates a dialog. If orbot is not installed, it shows an install dialog, else a
+ * dialog to enable orbot.
+ */
+public class OrbotRequiredDialogActivity extends FragmentActivity {
+
+ // to provide any previous crypto input into which proxy preference is merged
+ public static final String EXTRA_CRYPTO_INPUT = "extra_crypto_input";
+
+ public static final String RESULT_CRYPTO_INPUT = "result_crypto_input";
+
+ private CryptoInputParcel mCryptoInputParcel;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mCryptoInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT);
+ if (mCryptoInputParcel == null) {
+ mCryptoInputParcel = new CryptoInputParcel();
+ }
+ showDialog();
+ }
+
+ /**
+ * Displays an install or start orbot dialog depending on orbot's presence and state
+ */
+ public void showDialog() {
+ DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
+ public void run() {
+ Runnable ignoreTor = new Runnable() {
+ @Override
+ public void run() {
+ Intent intent = new Intent();
+ mCryptoInputParcel.addParcelableProxy(ParcelableProxy.getForNoProxy());
+ intent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+ };
+
+ Runnable dialogDismissed = new Runnable() {
+ @Override
+ public void run() {
+ finish();
+ }
+ };
+
+ if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, dialogDismissed,
+ Preferences.getPreferences(OrbotRequiredDialogActivity.this)
+ .getProxyPrefs(),
+ OrbotRequiredDialogActivity.this)) {
+ // no action required after all
+ Intent intent = new Intent();
+ intent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel);
+ setResult(RESULT_OK, intent);
+ }
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
index bb12cd7ff..d7224bd04 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
@@ -19,15 +19,16 @@ package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
-import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
+import android.support.v7.app.AlertDialog;
import android.text.InputType;
import android.text.method.PasswordTransformationMethod;
import android.view.ContextThemeWrapper;
@@ -58,6 +59,7 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
@@ -65,17 +67,22 @@ import org.sufficientlysecure.keychain.util.Preferences;
/**
* We can not directly create a dialog on the application context.
* This activity encapsulates a DialogFragment to emulate a dialog.
+ * NOTE: If no CryptoInputParcel is passed via EXTRA_CRYPTO_INPUT, the CryptoInputParcel is created
+ * internally and is NOT meant to be used by signing operations before adding a signature time
*/
public class PassphraseDialogActivity extends FragmentActivity {
public static final String RESULT_CRYPTO_INPUT = "result_data";
public static final String EXTRA_REQUIRED_INPUT = "required_input";
public static final String EXTRA_SUBKEY_ID = "secret_key_id";
+ public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
// special extra for OpenPgpService
public static final String EXTRA_SERVICE_INTENT = "data";
private long mSubKeyId;
+ private CryptoInputParcel mCryptoInputParcel;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -89,6 +96,15 @@ public class PassphraseDialogActivity extends FragmentActivity {
);
}
+ mCryptoInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT);
+
+ if (mCryptoInputParcel == null) {
+ // not all usages of PassphraseActivity are from CryptoInputOperation
+ // NOTE: This CryptoInputParcel cannot be used for signing operations without setting
+ // signature time
+ mCryptoInputParcel = new CryptoInputParcel();
+ }
+
// this activity itself has no content view (see manifest)
if (getIntent().hasExtra(EXTRA_SUBKEY_ID)) {
@@ -112,7 +128,8 @@ public class PassphraseDialogActivity extends FragmentActivity {
SecretKeyType.PASSPHRASE_EMPTY) {
// also return passphrase back to activity
Intent returnIntent = new Intent();
- returnIntent.putExtra(RESULT_CRYPTO_INPUT, new CryptoInputParcel(new Passphrase("")));
+ mCryptoInputParcel.mPassphrase = new Passphrase("");
+ returnIntent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel);
setResult(RESULT_OK, returnIntent);
finish();
return;
@@ -136,8 +153,8 @@ public class PassphraseDialogActivity extends FragmentActivity {
}
@Override
- protected void onResume() {
- super.onResume();
+ protected void onResumeFragments() {
+ super.onResumeFragments();
/* Show passphrase dialog to cache a new passphrase the user enters for using it later for
* encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
@@ -175,14 +192,12 @@ public class PassphraseDialogActivity extends FragmentActivity {
private Intent mServiceIntent;
+ @NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
- // if the dialog is displayed from the application class, design is missing
- // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
- ContextThemeWrapper theme = new ContextThemeWrapper(activity,
- R.style.Theme_AppCompat_Light_Dialog);
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
mSubKeyId = getArguments().getLong(EXTRA_SUBKEY_ID);
mServiceIntent = getArguments().getParcelable(EXTRA_SERVICE_INTENT);
@@ -299,10 +314,10 @@ public class PassphraseDialogActivity extends FragmentActivity {
mPassphraseEditText.setImeActionLabel(getString(android.R.string.ok), EditorInfo.IME_ACTION_DONE);
mPassphraseEditText.setOnEditorActionListener(this);
- if (keyType == CanonicalizedSecretKey.SecretKeyType.DIVERT_TO_CARD && Preferences.getPreferences(activity).useNumKeypadForYubiKeyPin()) {
- mPassphraseEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_TEXT_VARIATION_PASSWORD);
- } else if (keyType == CanonicalizedSecretKey.SecretKeyType.PIN) {
- mPassphraseEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ if ((keyType == CanonicalizedSecretKey.SecretKeyType.DIVERT_TO_CARD && Preferences.getPreferences(activity).useNumKeypadForYubiKeyPin())
+ || keyType == CanonicalizedSecretKey.SecretKeyType.PIN) {
+ mPassphraseEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
+ mPassphraseEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());
} else {
mPassphraseEditText.setRawInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
@@ -328,11 +343,16 @@ public class PassphraseDialogActivity extends FragmentActivity {
public void onClick(View v) {
final Passphrase passphrase = new Passphrase(mPassphraseEditText);
+ CryptoInputParcel cryptoInputParcel =
+ ((PassphraseDialogActivity) getActivity()).mCryptoInputParcel;
+
// Early breakout if we are dealing with a symmetric key
if (mSecretRing == null) {
- PassphraseCacheService.addCachedPassphrase(getActivity(),
- Constants.key.symmetric, Constants.key.symmetric, passphrase,
- getString(R.string.passp_cache_notif_pwd));
+ if (cryptoInputParcel.mCachePassphrase) {
+ PassphraseCacheService.addCachedPassphrase(getActivity(),
+ Constants.key.symmetric, Constants.key.symmetric, passphrase,
+ getString(R.string.passp_cache_notif_pwd));
+ }
finishCaching(passphrase);
return;
@@ -385,15 +405,24 @@ public class PassphraseDialogActivity extends FragmentActivity {
return;
}
- // cache the new passphrase
- Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
+ // cache the new passphrase as specified in CryptoInputParcel
+ Log.d(Constants.TAG, "Everything okay!");
- try {
- PassphraseCacheService.addCachedPassphrase(getActivity(),
- mSecretRing.getMasterKeyId(), mSubKeyId, passphrase,
- mSecretRing.getPrimaryUserIdWithFallback());
- } catch (PgpKeyNotFoundException e) {
- Log.e(Constants.TAG, "adding of a passphrase failed", e);
+ CryptoInputParcel cryptoInputParcel
+ = ((PassphraseDialogActivity) getActivity()).mCryptoInputParcel;
+
+ if (cryptoInputParcel.mCachePassphrase) {
+ Log.d(Constants.TAG, "Caching entered passphrase");
+
+ try {
+ PassphraseCacheService.addCachedPassphrase(getActivity(),
+ mSecretRing.getMasterKeyId(), mSubKeyId, passphrase,
+ mSecretRing.getPrimaryUserIdWithFallback());
+ } catch (PgpKeyNotFoundException e) {
+ Log.e(Constants.TAG, "adding of a passphrase failed", e);
+ }
+ } else {
+ Log.d(Constants.TAG, "Not caching entered passphrase!");
}
finishCaching(passphrase);
@@ -409,9 +438,12 @@ public class PassphraseDialogActivity extends FragmentActivity {
return;
}
- CryptoInputParcel inputParcel = new CryptoInputParcel(null, passphrase);
+ CryptoInputParcel inputParcel =
+ ((PassphraseDialogActivity) getActivity()).mCryptoInputParcel;
+ inputParcel.mPassphrase = passphrase;
if (mServiceIntent != null) {
- CryptoInputParcelCacheService.addCryptoInputParcel(getActivity(), mServiceIntent, inputParcel);
+ CryptoInputParcelCacheService.addCryptoInputParcel(getActivity(), mServiceIntent,
+ inputParcel);
getActivity().setResult(RESULT_OK, mServiceIntent);
} else {
// also return passphrase back to activity
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java
index 2e838535d..e55494145 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java
@@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi;
-import android.app.AlertDialog;
+import android.support.v7.app.AlertDialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
@@ -43,7 +43,9 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -207,7 +209,7 @@ public class PassphraseWizardActivity extends FragmentActivity {
// transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit();
}
} catch (IOException | FormatException e) {
- e.printStackTrace();
+ Log.e(Constants.TAG, "Failed to write on NFC tag", e);
}
} else if (readNFC && AUTHENTICATION.equals(selectedAction)) {
@@ -232,7 +234,7 @@ public class PassphraseWizardActivity extends FragmentActivity {
}
}
} catch (IOException | FormatException e) {
- e.printStackTrace();
+ Log.e(Constants.TAG, "Failed to read NFC tag", e);
}
}
}
@@ -263,7 +265,7 @@ public class PassphraseWizardActivity extends FragmentActivity {
try {
password = readText(ndefRecord);
} catch (UnsupportedEncodingException e) {
- e.printStackTrace();
+ Log.e(Constants.TAG, "Failed to read password from tag", e);
}
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java
new file mode 100644
index 000000000..2a00e8b70
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@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
+ * 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;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+import android.view.ContextThemeWrapper;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
+import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
+
+public class RetryUploadDialogActivity extends FragmentActivity {
+
+ public static final String EXTRA_CRYPTO_INPUT = "extra_crypto_input";
+
+ public static final String RESULT_CRYPTO_INPUT = "result_crypto_input";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ UploadRetryDialogFragment.newInstance().show(getSupportFragmentManager(),
+ "uploadRetryDialog");
+ }
+
+ public static class UploadRetryDialogFragment extends DialogFragment {
+ public static UploadRetryDialogFragment newInstance() {
+ return new UploadRetryDialogFragment();
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(getActivity());
+
+ CustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(theme);
+ dialogBuilder.setTitle(R.string.retry_up_dialog_title);
+ dialogBuilder.setMessage(R.string.retry_up_dialog_message);
+
+ dialogBuilder.setNegativeButton(R.string.retry_up_dialog_btn_cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ getActivity().setResult(RESULT_CANCELED);
+ getActivity().finish();
+ }
+ });
+
+ dialogBuilder.setPositiveButton(R.string.retry_up_dialog_btn_reupload,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intent = new Intent();
+ intent.putExtra(RESULT_CRYPTO_INPUT, getActivity()
+ .getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT));
+ getActivity().setResult(RESULT_OK, intent);
+ getActivity().finish();
+ }
+ });
+
+ return dialogBuilder.show();
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java
index a1cb77546..534dbfd05 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java
@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
@@ -81,7 +82,7 @@ public class SafeSlingerActivity extends BaseActivity
});
ImageView buttonIcon = (ImageView) findViewById(R.id.safe_slinger_button_image);
- buttonIcon.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
+ buttonIcon.setColorFilter(FormattingUtils.getColorFromAttr(this, R.attr.colorTertiaryText),
PorterDuff.Mode.SRC_IN);
View button = findViewById(R.id.safe_slinger_button);
@@ -144,7 +145,7 @@ public class SafeSlingerActivity extends BaseActivity
cache.writeCache(it.size(), it.iterator());
mOperationHelper =
- new CryptoOperationHelper(this, this, R.string.progress_importing);
+ new CryptoOperationHelper(1, this, this, R.string.progress_importing);
mKeyList = null;
mKeyserver = null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
index a552e1c55..2fe868b8b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
@@ -18,14 +18,21 @@
package org.sufficientlysecure.keychain.ui;
+import android.annotation.TargetApi;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
@@ -33,8 +40,12 @@ import android.widget.LinearLayout;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.AppCompatPreferenceActivity;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
+import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
import java.util.List;
@@ -42,15 +53,21 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD";
public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
+ public static final String ACTION_PREFS_PROXY = "org.sufficientlysecure.keychain.ui.PREFS_PROXY";
+ public static final String ACTION_PREFS_GUI = "org.sufficientlysecure.keychain.ui.PREFS_GUI";
public static final int REQUEST_CODE_KEYSERVER_PREF = 0x00007005;
private PreferenceScreen mKeyServerPreference = null;
private static Preferences sPreferences;
+ private ThemeChanger mThemeChanger;
@Override
protected void onCreate(Bundle savedInstanceState) {
sPreferences = Preferences.getPreferences(this);
+
+ mThemeChanger = new ThemeChanger(this);
+ mThemeChanger.changeTheme();
super.onCreate(savedInstanceState);
setupToolbar();
@@ -95,6 +112,21 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
initializeUseNumKeypadForYubiKeyPin(
(CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN));
+ } else if (action != null && action.equals(ACTION_PREFS_GUI)) {
+ addPreferencesFromResource(R.xml.gui_preferences);
+
+ initializeTheme((ListPreference) findPreference(Constants.Pref.THEME));
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (mThemeChanger.changeTheme()) {
+ Intent intent = getIntent();
+ finish();
+ startActivity(intent);
}
}
@@ -124,27 +156,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
}
@Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case REQUEST_CODE_KEYSERVER_PREF: {
- if (resultCode == RESULT_CANCELED || data == null) {
- return;
- }
- String servers[] = data
- .getStringArrayExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS);
- sPreferences.setKeyServers(servers);
- mKeyServerPreference.setSummary(keyserverSummary(this));
- break;
- }
-
- default: {
- super.onActivityResult(requestCode, resultCode, data);
- break;
- }
- }
- }
-
- @Override
public void onBuildHeaders(List<Header> target) {
super.onBuildHeaders(target);
loadHeadersFromResource(R.xml.preference_headers, target);
@@ -190,12 +201,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_KEYSERVER_PREF: {
- if (resultCode == RESULT_CANCELED || data == null) {
- return;
- }
- String servers[] = data
- .getStringArrayExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS);
- sPreferences.setKeyServers(servers);
+ // update preference, in case it changed
mKeyServerPreference.setSummary(keyserverSummary(getActivity()));
break;
}
@@ -234,9 +240,236 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
}
}
+ public static class ProxyPrefsFragment extends PreferenceFragment {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ new Initializer(this).initialize();
+
+ }
+
+ public static class Initializer {
+ private CheckBoxPreference mUseTor;
+ private CheckBoxPreference mUseNormalProxy;
+ private EditTextPreference mProxyHost;
+ private EditTextPreference mProxyPort;
+ private ListPreference mProxyType;
+ private PreferenceActivity mActivity;
+ private PreferenceFragment mFragment;
+
+ public Initializer(PreferenceFragment fragment) {
+ mFragment = fragment;
+ }
+
+ public Initializer(PreferenceActivity activity) {
+ mActivity = activity;
+ }
+
+ public Preference automaticallyFindPreference(String key) {
+ if (mFragment != null) {
+ return mFragment.findPreference(key);
+ } else {
+ return mActivity.findPreference(key);
+ }
+ }
+
+ public void initialize() {
+ // makes android's preference framework write to our file instead of default
+ // This allows us to use the "persistent" attribute to simplify code
+ if (mFragment != null) {
+ Preferences.setPreferenceManagerFileAndMode(mFragment.getPreferenceManager());
+ // Load the preferences from an XML resource
+ mFragment.addPreferencesFromResource(R.xml.proxy_prefs);
+ } else {
+ Preferences.setPreferenceManagerFileAndMode(mActivity.getPreferenceManager());
+ // Load the preferences from an XML resource
+ mActivity.addPreferencesFromResource(R.xml.proxy_prefs);
+ }
+
+ mUseTor = (CheckBoxPreference) automaticallyFindPreference(Constants.Pref.USE_TOR_PROXY);
+ mUseNormalProxy = (CheckBoxPreference) automaticallyFindPreference(Constants.Pref.USE_NORMAL_PROXY);
+ mProxyHost = (EditTextPreference) automaticallyFindPreference(Constants.Pref.PROXY_HOST);
+ mProxyPort = (EditTextPreference) automaticallyFindPreference(Constants.Pref.PROXY_PORT);
+ mProxyType = (ListPreference) automaticallyFindPreference(Constants.Pref.PROXY_TYPE);
+ initializeUseTorPref();
+ initializeUseNormalProxyPref();
+ initializeEditTextPreferences();
+ initializeProxyTypePreference();
+
+ if (mUseTor.isChecked()) {
+ disableNormalProxyPrefs();
+ }
+ else if (mUseNormalProxy.isChecked()) {
+ disableUseTorPrefs();
+ } else {
+ disableNormalProxySettings();
+ }
+ }
+
+ private void initializeUseTorPref() {
+ mUseTor.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Activity activity = mFragment != null ? mFragment.getActivity() : mActivity;
+ if ((Boolean) newValue) {
+ boolean installed = OrbotHelper.isOrbotInstalled(activity);
+ if (!installed) {
+ Log.d(Constants.TAG, "Prompting to install Tor");
+ OrbotHelper.getPreferenceInstallDialogFragment().show(activity.getFragmentManager(),
+ "installDialog");
+ // don't let the user check the box until he's installed orbot
+ return false;
+ } else {
+ disableNormalProxyPrefs();
+ // let the enable tor box be checked
+ return true;
+ }
+ } else {
+ // we're unchecking Tor, so enable other proxy
+ enableNormalProxyCheckbox();
+ return true;
+ }
+ }
+ });
+ }
+
+ private void initializeUseNormalProxyPref() {
+ mUseNormalProxy.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if ((Boolean) newValue) {
+ disableUseTorPrefs();
+ enableNormalProxySettings();
+ } else {
+ enableUseTorPrefs();
+ disableNormalProxySettings();
+ }
+ return true;
+ }
+ });
+ }
+
+ private void initializeEditTextPreferences() {
+ mProxyHost.setSummary(mProxyHost.getText());
+ mProxyPort.setSummary(mProxyPort.getText());
+
+ mProxyHost.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Activity activity = mFragment != null ? mFragment.getActivity() : mActivity;
+ if (TextUtils.isEmpty((String) newValue)) {
+ Notify.create(
+ activity,
+ R.string.pref_proxy_host_err_invalid,
+ Notify.Style.ERROR
+ ).show();
+ return false;
+ } else {
+ mProxyHost.setSummary((CharSequence) newValue);
+ return true;
+ }
+ }
+ });
+
+ mProxyPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Activity activity = mFragment != null ? mFragment.getActivity() : mActivity;
+ try {
+ int port = Integer.parseInt((String) newValue);
+ if (port < 0 || port > 65535) {
+ Notify.create(
+ activity,
+ R.string.pref_proxy_port_err_invalid,
+ Notify.Style.ERROR
+ ).show();
+ return false;
+ }
+ // no issues, save port
+ mProxyPort.setSummary("" + port);
+ return true;
+ } catch (NumberFormatException e) {
+ Notify.create(
+ activity,
+ R.string.pref_proxy_port_err_invalid,
+ Notify.Style.ERROR
+ ).show();
+ return false;
+ }
+ }
+ });
+ }
+
+ private void initializeProxyTypePreference() {
+ mProxyType.setSummary(mProxyType.getEntry());
+
+ mProxyType.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ CharSequence entry = mProxyType.getEntries()[mProxyType.findIndexOfValue((String) newValue)];
+ mProxyType.setSummary(entry);
+ return true;
+ }
+ });
+ }
+
+ private void disableNormalProxyPrefs() {
+ mUseNormalProxy.setChecked(false);
+ mUseNormalProxy.setEnabled(false);
+ disableNormalProxySettings();
+ }
+
+ private void enableNormalProxyCheckbox() {
+ mUseNormalProxy.setEnabled(true);
+ }
+
+ private void enableNormalProxySettings() {
+ mProxyHost.setEnabled(true);
+ mProxyPort.setEnabled(true);
+ mProxyType.setEnabled(true);
+ }
+
+ private void disableNormalProxySettings() {
+ mProxyHost.setEnabled(false);
+ mProxyPort.setEnabled(false);
+ mProxyType.setEnabled(false);
+ }
+
+ private void disableUseTorPrefs() {
+ mUseTor.setChecked(false);
+ mUseTor.setEnabled(false);
+ }
+
+ private void enableUseTorPrefs() {
+ mUseTor.setEnabled(true);
+ }
+ }
+ }
+
+ /**
+ * This fragment shows gui preferences.
+ */
+ public static class GuiPrefsFragment extends PreferenceFragment {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.gui_preferences);
+
+ initializeTheme((ListPreference) findPreference(Constants.Pref.THEME));
+ }
+ }
+
protected boolean isValidFragment(String fragmentName) {
return AdvancedPrefsFragment.class.getName().equals(fragmentName)
|| CloudSearchPrefsFragment.class.getName().equals(fragmentName)
+ || ProxyPrefsFragment.class.getName().equals(fragmentName)
+ || GuiPrefsFragment.class.getName().equals(fragmentName)
|| super.isValidFragment(fragmentName);
}
@@ -265,6 +498,19 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
});
}
+ private static void initializeTheme(final ListPreference mTheme) {
+ mTheme.setValue(sPreferences.getTheme());
+ mTheme.setSummary(mTheme.getEntry());
+ mTheme.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ mTheme.setValue((String) newValue);
+ mTheme.setSummary(mTheme.getEntry());
+ sPreferences.setTheme((String) newValue);
+ return false;
+ }
+ });
+ }
+
private static void initializeSearchKeyserver(final CheckBoxPreference mSearchKeyserver) {
Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs();
mSearchKeyserver.setChecked(prefs.searchKeyserver);
@@ -295,7 +541,8 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
String[] servers = sPreferences.getKeyServers();
String serverSummary = context.getResources().getQuantityString(
R.plurals.n_keyservers, servers.length, servers.length);
- return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences.getPreferredKeyserver();
+ return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences
+ .getPreferredKeyserver();
}
private static void initializeUseDefaultYubiKeyPin(final CheckBoxPreference mUseDefaultYubiKeyPin) {
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 dc203756f..f61ada84f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java
@@ -17,89 +17,23 @@
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;
-import android.view.ViewGroup;
-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;
-import java.util.Vector;
-
-public class SettingsKeyServerActivity extends BaseActivity implements OnClickListener,
- EditorListener {
+public class SettingsKeyServerActivity extends BaseActivity {
public static final String EXTRA_KEY_SERVERS = "key_servers";
- private LayoutInflater mInflater;
- private ViewGroup mEditors;
- private View mAdd;
- private View mRotate;
- private TextView mTitle;
- private TextView mSummary;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // Inflate a "Done"/"Cancel" custom action bar view
- setFullScreenDialogDoneClose(R.string.btn_save,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- okClicked();
- }
- },
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- cancelClicked();
- }
- });
-
- mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- mTitle = (TextView) findViewById(R.id.title);
- mSummary = (TextView) findViewById(R.id.summary);
- mSummary.setText(getText(R.string.label_first_keyserver_is_used));
-
- mTitle.setText(R.string.label_keyservers);
-
- mEditors = (ViewGroup) findViewById(R.id.editors);
- mAdd = findViewById(R.id.add);
- mAdd.setOnClickListener(this);
-
- mRotate = findViewById(R.id.rotate);
- mRotate.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- Vector<String> servers = serverList();
- String first = servers.get(0);
- if (first != null) {
- servers.remove(0);
- servers.add(first);
- String[] dummy = {};
- makeServerList(servers.toArray(dummy));
- }
- }
- });
-
Intent intent = getIntent();
String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS);
- makeServerList(servers);
+ loadFragment(savedInstanceState, servers);
}
@Override
@@ -107,118 +41,22 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi
setContentView(R.layout.key_server_preference);
}
- private void makeServerList(String[] servers) {
- if (servers != null) {
- mEditors.removeAllViews();
- for (String serv : servers) {
- KeyServerEditor view = (KeyServerEditor) mInflater.inflate(
- R.layout.key_server_editor, mEditors, false);
- view.setEditorListener(this);
- view.setValue(serv);
- mEditors.addView(view);
- }
+ private void loadFragment(Bundle savedInstanceState, String[] keyservers) {
+ // However, if we're being restored from a previous state,
+ // then we don't need to do anything and should return or else
+ // we could end up with overlapping fragments.
+ if (savedInstanceState != null) {
+ return;
}
- }
-
- public void onDeleted(Editor editor, boolean wasNewItem) {
- // nothing to do
- }
- @Override
- public void onEdited() {
+ SettingsKeyserverFragment fragment = SettingsKeyserverFragment.newInstance(keyservers);
- }
-
- // 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);
- 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);
- }
-
- private void cancelClicked() {
- setResult(RESULT_CANCELED, null);
- finish();
- }
-
- private Vector<String> serverList() {
- Vector<String> servers = new Vector<>();
- for (int i = 0; i < mEditors.getChildCount(); ++i) {
- KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i);
- String tmp = editor.getValue();
- if (tmp.length() > 0) {
- servers.add(tmp);
- }
- }
- return servers;
- }
-
- private void okClicked() {
- Intent data = new Intent();
- Vector<String> servers = new Vector<>();
- for (int i = 0; i < mEditors.getChildCount(); ++i) {
- KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i);
- String tmp = editor.getValue();
- if (tmp.length() > 0) {
- servers.add(tmp);
- }
- }
- String[] dummy = new String[0];
- data.putExtra(EXTRA_KEY_SERVERS, servers.toArray(dummy));
- setResult(RESULT_OK, data);
- finish();
+ // Add the fragment to the 'fragment_container' FrameLayout
+ // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.keyserver_settings_fragment_container, fragment)
+ .commitAllowingStateLoss();
+ // do it immediately!
+ getSupportFragmentManager().executePendingTransactions();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java
new file mode 100644
index 000000000..2ae64d90b
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2012-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@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
+ * 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;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.dialog.AddEditKeyserverDialogFragment;
+import org.sufficientlysecure.keychain.ui.util.recyclerview.ItemTouchHelperAdapter;
+import org.sufficientlysecure.keychain.ui.util.recyclerview.ItemTouchHelperViewHolder;
+import org.sufficientlysecure.keychain.ui.util.recyclerview.ItemTouchHelperDragCallback;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener;
+import org.sufficientlysecure.keychain.util.Preferences;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class SettingsKeyserverFragment extends Fragment implements RecyclerItemClickListener.OnItemClickListener {
+
+ private static final String ARG_KEYSERVER_ARRAY = "arg_keyserver_array";
+ private ItemTouchHelper mItemTouchHelper;
+
+ private ArrayList<String> mKeyservers;
+ private KeyserverListAdapter mAdapter;
+
+ public static SettingsKeyserverFragment newInstance(String[] keyservers) {
+ Bundle args = new Bundle();
+ args.putStringArray(ARG_KEYSERVER_ARRAY, keyservers);
+
+ SettingsKeyserverFragment fragment = new SettingsKeyserverFragment();
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
+ savedInstanceState) {
+
+ return inflater.inflate(R.layout.settings_keyserver_fragment, null);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ String keyservers[] = getArguments().getStringArray(ARG_KEYSERVER_ARRAY);
+ mKeyservers = new ArrayList<>(Arrays.asList(keyservers));
+
+ mAdapter = new KeyserverListAdapter(mKeyservers);
+
+ RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.keyserver_recycler_view);
+ // recyclerView.setHasFixedSize(true); // the size of the first item changes
+ recyclerView.setAdapter(mAdapter);
+ recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
+
+
+ ItemTouchHelper.Callback callback = new ItemTouchHelperDragCallback(mAdapter);
+ mItemTouchHelper = new ItemTouchHelper(callback);
+ mItemTouchHelper.attachToRecyclerView(recyclerView);
+
+ // for clicks
+ recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), this));
+
+ // can't use item decoration because it doesn't move with drag and drop
+ // recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
+
+ // We have a menu item to show in action bar.
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
+ inflater.inflate(R.menu.keyserver_pref_menu, menu);
+
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+
+ case R.id.menu_add_keyserver:
+ startAddKeyserverDialog();
+ return true;
+
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void startAddKeyserverDialog() {
+ // keyserver and position have no meaning
+ startEditKeyserverDialog(AddEditKeyserverDialogFragment.DialogAction.ADD, null, -1);
+ }
+
+ private void startEditKeyserverDialog(AddEditKeyserverDialogFragment.DialogAction action,
+ String keyserver, final int position) {
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ Bundle data = message.getData();
+ switch (message.what) {
+ case AddEditKeyserverDialogFragment.MESSAGE_OKAY: {
+ boolean deleted =
+ data.getBoolean(AddEditKeyserverDialogFragment.MESSAGE_KEYSERVER_DELETED
+ , false);
+ if (deleted) {
+ Notify.create(getActivity(),
+ getActivity().getString(
+ R.string.keyserver_preference_deleted, mKeyservers.get(position)),
+ Notify.Style.OK)
+ .show();
+ deleteKeyserver(position);
+ return;
+ }
+ boolean verified =
+ data.getBoolean(AddEditKeyserverDialogFragment.MESSAGE_VERIFIED);
+ if (verified) {
+ Notify.create(getActivity(),
+ R.string.add_keyserver_verified, Notify.Style.OK).show();
+ } else {
+ Notify.create(getActivity(),
+ R.string.add_keyserver_without_verification,
+ Notify.Style.WARN).show();
+ }
+ String keyserver = data.getString(
+ AddEditKeyserverDialogFragment.MESSAGE_KEYSERVER);
+
+ AddEditKeyserverDialogFragment.DialogAction dialogAction
+ = (AddEditKeyserverDialogFragment.DialogAction) data.getSerializable(
+ AddEditKeyserverDialogFragment.MESSAGE_DIALOG_ACTION);
+ switch (dialogAction) {
+ case ADD:
+ addKeyserver(keyserver);
+ break;
+ case EDIT:
+ editKeyserver(keyserver, position);
+ break;
+ }
+ break;
+ }
+ case AddEditKeyserverDialogFragment.MESSAGE_VERIFICATION_FAILED: {
+ AddEditKeyserverDialogFragment.FailureReason failureReason =
+ (AddEditKeyserverDialogFragment.FailureReason) data.getSerializable(
+ AddEditKeyserverDialogFragment.MESSAGE_FAILURE_REASON);
+ switch (failureReason) {
+ case CONNECTION_FAILED: {
+ Notify.create(getActivity(),
+ R.string.add_keyserver_connection_failed,
+ Notify.Style.ERROR).show();
+ break;
+ }
+ case INVALID_URL: {
+ Notify.create(getActivity(),
+ 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);
+ AddEditKeyserverDialogFragment dialogFragment = AddEditKeyserverDialogFragment
+ .newInstance(messenger, action, keyserver, position);
+ dialogFragment.show(getFragmentManager(), "addKeyserverDialog");
+ }
+
+ private void addKeyserver(String keyserver) {
+ mKeyservers.add(keyserver);
+ mAdapter.notifyItemInserted(mKeyservers.size() - 1);
+ saveKeyserverList();
+ }
+
+ private void editKeyserver(String newKeyserver, int position) {
+ mKeyservers.set(position, newKeyserver);
+ mAdapter.notifyItemChanged(position);
+ saveKeyserverList();
+ }
+
+ private void deleteKeyserver(int position) {
+ if (mKeyservers.size() == 1) {
+ Notify.create(getActivity(), R.string.keyserver_preference_cannot_delete_last,
+ Notify.Style.ERROR).show();
+ return;
+ }
+ mKeyservers.remove(position);
+ // we use this
+ mAdapter.notifyItemRemoved(position);
+ if (position == 0 && mKeyservers.size() > 0) {
+ // if we deleted the first item, we need the adapter to redraw the new first item
+ mAdapter.notifyItemChanged(0);
+ }
+ saveKeyserverList();
+ }
+
+ private void saveKeyserverList() {
+ String servers[] = mKeyservers.toArray(new String[mKeyservers.size()]);
+ Preferences.getPreferences(getActivity()).setKeyServers(servers);
+ }
+
+ @Override
+ public void onItemClick(View view, int position) {
+ startEditKeyserverDialog(AddEditKeyserverDialogFragment.DialogAction.EDIT,
+ mKeyservers.get(position), position);
+ }
+
+ public class KeyserverListAdapter extends RecyclerView.Adapter<KeyserverListAdapter.ViewHolder>
+ implements ItemTouchHelperAdapter {
+
+ // to update the ViewHolder associated with first item, for when an item is deleted
+ private ViewHolder mFirstItem;
+
+ private final List<String> mKeyservers;
+
+ public KeyserverListAdapter(List<String> keyservers) {
+ mKeyservers = keyservers;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.settings_keyserver_item, parent, false);
+ ViewHolder viewHolder = new ViewHolder(view);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(final ViewHolder holder, int position) {
+ if (position == 0) {
+ mFirstItem = holder;
+ }
+ holder.keyserverUrl.setText(mKeyservers.get(position));
+
+ // Start a drag whenever the handle view it touched
+ holder.dragHandleView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+ mItemTouchHelper.startDrag(holder);
+ }
+ return false;
+ }
+ });
+
+ selectUnselectKeyserver(holder, position);
+ }
+
+ private void selectUnselectKeyserver(ViewHolder holder, int position) {
+
+ if (position == 0) {
+ holder.showAsSelectedKeyserver();
+ } else {
+ holder.showAsUnselectedKeyserver();
+ }
+ }
+
+ @Override
+ public void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target,
+ int fromPosition, int toPosition) {
+ Collections.swap(mKeyservers, fromPosition, toPosition);
+ saveKeyserverList();
+ selectUnselectKeyserver((ViewHolder) target, fromPosition);
+ // we don't want source to change color while dragging, therefore we just set
+ // isSelectedKeyserver instead of selectUnselectKeyserver
+ ((ViewHolder) source).isSelectedKeyserver = toPosition == 0;
+
+ notifyItemMoved(fromPosition, toPosition);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mKeyservers.size();
+ }
+
+ public class ViewHolder extends RecyclerView.ViewHolder implements
+ ItemTouchHelperViewHolder {
+
+ public final ViewGroup outerLayout;
+ public final TextView selectedServerLabel;
+ public final TextView keyserverUrl;
+ public final ImageView dragHandleView;
+
+ private boolean isSelectedKeyserver = false;
+
+ public ViewHolder(View itemView) {
+ super(itemView);
+ outerLayout = (ViewGroup) itemView.findViewById(R.id.outer_layout);
+ selectedServerLabel = (TextView) itemView.findViewById(
+ R.id.selected_keyserver_title);
+ keyserverUrl = (TextView) itemView.findViewById(R.id.keyserver_tv);
+ dragHandleView = (ImageView) itemView.findViewById(R.id.drag_handle);
+
+ itemView.setClickable(true);
+ }
+
+ public void showAsSelectedKeyserver() {
+ isSelectedKeyserver = true;
+ selectedServerLabel.setVisibility(View.VISIBLE);
+ outerLayout.setBackgroundColor(getResources().getColor(R.color.android_green_dark));
+ }
+
+ public void showAsUnselectedKeyserver() {
+ isSelectedKeyserver = false;
+ selectedServerLabel.setVisibility(View.GONE);
+ outerLayout.setBackgroundColor(Color.WHITE);
+ }
+
+ @Override
+ public void onItemSelected() {
+ selectedServerLabel.setVisibility(View.GONE);
+ itemView.setBackgroundColor(Color.LTGRAY);
+ }
+
+ @Override
+ public void onItemClear() {
+ if (isSelectedKeyserver) {
+ showAsSelectedKeyserver();
+ } else {
+ showAsUnselectedKeyserver();
+ }
+ }
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
index 8b49f3b96..0415128a2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
@@ -26,7 +26,6 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
-import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -108,7 +107,7 @@ public class UploadKeyActivity extends BaseActivity
String server = (String) mKeyServerSpinner.getSelectedItem();
mKeyserver = server;
- mUploadOpHelper = new CryptoOperationHelper(this, this, R.string.progress_uploading);
+ mUploadOpHelper = new CryptoOperationHelper(1, this, this, R.string.progress_uploading);
mUploadOpHelper.cryptoOperation();
}
@@ -132,8 +131,7 @@ public class UploadKeyActivity extends BaseActivity
@Override
public void onCryptoOperationSuccess(ExportResult result) {
- Toast.makeText(UploadKeyActivity.this, R.string.msg_crt_upload_success,
- Toast.LENGTH_SHORT).show();
+ result.createNotify(this).show();
}
@Override
@@ -143,7 +141,7 @@ public class UploadKeyActivity extends BaseActivity
@Override
public void onCryptoOperationError(ExportResult result) {
- // TODO: Implement proper log for key upload then show error
+ result.createNotify(this).show();
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index d3849c892..1d0e085da 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -31,8 +31,6 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
@@ -52,11 +50,12 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
+
import com.getbase.floatingactionbutton.FloatingActionButton;
+
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
-import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
@@ -66,13 +65,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
-import org.sufficientlysecure.keychain.service.KeychainService;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
-import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
@@ -88,7 +82,6 @@ import org.sufficientlysecure.keychain.util.Preferences;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashMap;
public class ViewKeyActivity extends BaseNfcActivity implements
LoaderManager.LoaderCallbacks<Cursor>,
@@ -99,11 +92,12 @@ public class ViewKeyActivity extends BaseNfcActivity implements
public static final String EXTRA_NFC_FINGERPRINTS = "nfc_fingerprints";
static final int REQUEST_QR_FINGERPRINT = 1;
- static final int REQUEST_DELETE = 2;
- static final int REQUEST_EXPORT = 3;
+ static final int REQUEST_BACKUP = 2;
+ static final int REQUEST_CERTIFY = 3;
+ static final int REQUEST_DELETE = 4;
+
public static final String EXTRA_DISPLAY_RESULT = "display_result";
- ExportHelper mExportHelper;
ProviderHelper mProviderHelper;
protected Uri mDataUri;
@@ -148,13 +142,17 @@ public class ViewKeyActivity extends BaseNfcActivity implements
private String mFingerprint;
private long mMasterKeyId;
+ private byte[] mNfcFingerprints;
+ private String mNfcUserId;
+ private byte[] mNfcAid;
+
@SuppressLint("InflateParams")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mExportHelper = new ExportHelper(this);
mProviderHelper = new ProviderHelper(this);
+ mOperationHelper = new CryptoOperationHelper<>(1, this, this, null);
setTitle(null);
@@ -325,31 +323,11 @@ public class ViewKeyActivity extends BaseNfcActivity implements
return true;
}
case R.id.menu_key_view_export_file: {
- try {
- if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) {
- exportToFile(mDataUri, mExportHelper, mProviderHelper);
- return true;
- }
-
- startPassphraseActivity(REQUEST_EXPORT);
- } catch (PassphraseCacheService.KeyNotFoundException e) {
- // This happens when the master key is stripped
- exportToFile(mDataUri, mExportHelper, mProviderHelper);
- }
+ startPassphraseActivity(REQUEST_BACKUP);
return true;
}
case R.id.menu_key_view_delete: {
- try {
- if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) {
- deleteKey();
- return true;
- }
-
- startPassphraseActivity(REQUEST_DELETE);
- } catch (PassphraseCacheService.KeyNotFoundException e) {
- // This happens when the master key is stripped
- deleteKey();
- }
+ deleteKey();
return true;
}
case R.id.menu_key_view_advanced: {
@@ -382,6 +360,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem editKey = menu.findItem(R.id.menu_key_view_edit);
editKey.setVisible(mIsSecret);
+ MenuItem exportKey = menu.findItem(R.id.menu_key_view_export_file);
+ exportKey.setVisible(mIsSecret);
MenuItem certifyFingerprint = menu.findItem(R.id.menu_key_view_certify_fingerprint);
certifyFingerprint.setVisible(!mIsSecret && !mIsVerified && !mIsExpired && !mIsRevoked);
@@ -399,37 +379,14 @@ public class ViewKeyActivity extends BaseNfcActivity implements
Intent intent = new Intent(this, CertifyFingerprintActivity.class);
intent.setData(dataUri);
- startCertifyIntent(intent);
+ startActivityForResult(intent, REQUEST_CERTIFY);
}
private void certifyImmediate() {
Intent intent = new Intent(this, CertifyKeyActivity.class);
intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId});
- startCertifyIntent(intent);
- }
-
- private void startCertifyIntent(Intent intent) {
- // Message is received after signing is done in KeychainService
- ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {
- @Override
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == MessageStatus.OKAY.ordinal()) {
- Bundle data = message.getData();
- CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
-
- result.createNotify(ViewKeyActivity.this).show();
- }
- }
- };
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
-
- startActivityForResult(intent, 0);
+ startActivityForResult(intent, REQUEST_CERTIFY);
}
private void showQrCodeDialog() {
@@ -454,99 +411,95 @@ public class ViewKeyActivity extends BaseNfcActivity implements
startActivityForResult(intent, requestCode);
}
- private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper) {
- try {
- Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri);
-
- HashMap<String, Object> data = providerHelper.getGenericData(
- baseUri,
- new String[] {KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET},
- new int[] {ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER});
-
- exportHelper.showExportKeysDialog(
- new long[] {(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
- Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0)
- );
- } catch (ProviderHelper.NotFoundException e) {
- Notify.create(this, R.string.error_key_not_found, Notify.Style.ERROR).show();
- Log.e(Constants.TAG, "Key not found", e);
- }
+ private void backupToFile() {
+ new ExportHelper(this).showExportKeysDialog(
+ mMasterKeyId, Constants.Path.APP_DIR_FILE, true);
}
private void deleteKey() {
- // Message is received after key is deleted
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.arg1 == MessageStatus.OKAY.ordinal()) {
- setResult(RESULT_CANCELED);
- finish();
- }
- }
- };
+ Intent deleteIntent = new Intent(this, DeleteKeyDialogActivity.class);
+
+ deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS,
+ new long[]{mMasterKeyId});
+ deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_HAS_SECRET, mIsSecret);
+ if (mIsSecret) {
+ // for upload in case key is secret
+ deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_KEYSERVER,
+ Preferences.getPreferences(this).getPreferredKeyserver());
+ }
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
- DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
- new long[] {mMasterKeyId});
- deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog");
+ startActivityForResult(deleteIntent, REQUEST_DELETE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mOperationHelper != null) {
- mOperationHelper.handleActivityResult(requestCode, resultCode, data);
+ if (mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
+ return;
+ }
+
+ if (resultCode != Activity.RESULT_OK) {
+ return;
}
- if (requestCode == REQUEST_QR_FINGERPRINT && resultCode == Activity.RESULT_OK) {
+ switch (requestCode) {
+ case REQUEST_QR_FINGERPRINT: {
- // If there is an EXTRA_RESULT, that's an error. Just show it.
- if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
- OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
- result.createNotify(this).show();
+ // If there is an EXTRA_RESULT, that's an error. Just show it.
+ if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(this).show();
+ return;
+ }
+
+ String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
+ if (fp == null) {
+ Notify.create(this, R.string.error_scan_fp, Notify.LENGTH_LONG, Style.ERROR).show();
+ return;
+ }
+ if (mFingerprint.equalsIgnoreCase(fp)) {
+ certifyImmediate();
+ } else {
+ Notify.create(this, R.string.error_scan_match, Notify.LENGTH_LONG, Style.ERROR).show();
+ }
return;
}
- String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
- if (fp == null) {
- Notify.create(this, "Error scanning fingerprint!",
- Notify.LENGTH_LONG, Notify.Style.ERROR).show();
+ case REQUEST_BACKUP: {
+ backupToFile();
return;
}
- if (mFingerprint.equalsIgnoreCase(fp)) {
- certifyImmediate();
- } else {
- Notify.create(this, "Fingerprints did not match!",
- Notify.LENGTH_LONG, Notify.Style.ERROR).show();
- }
- return;
- }
+ case REQUEST_CERTIFY: {
+ if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(this).show();
+ }
+ return;
+ }
- if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK) {
- deleteKey();
+ case REQUEST_DELETE: {
+ setResult(RESULT_OK, data);
+ finish();
+ return;
+ }
}
- if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK) {
- exportToFile(mDataUri, mExportHelper, mProviderHelper);
- }
+ super.onActivityResult(requestCode, resultCode, data);
- if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
- OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
- result.createNotify(this).show();
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
}
@Override
- protected void onNfcPerform() throws IOException {
+ protected void doNfcInBackground() throws IOException {
+
+ mNfcFingerprints = nfcGetFingerprints();
+ mNfcUserId = nfcGetUserId();
+ mNfcAid = nfcGetAid();
+ }
- final byte[] nfcFingerprints = nfcGetFingerprints();
- final String nfcUserId = nfcGetUserId();
- final byte[] nfcAid = nfcGetAid();
+ @Override
+ protected void onNfcPostExecute() throws IOException {
- long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints);
+ long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
try {
@@ -557,7 +510,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
// if the master key of that key matches this one, just show the yubikey dialog
if (KeyFormattingUtils.convertFingerprintToHex(candidateFp).equals(mFingerprint)) {
- showYubiKeyFragment(nfcFingerprints, nfcUserId, nfcAid);
+ showYubiKeyFragment(mNfcFingerprints, mNfcUserId, mNfcAid);
return;
}
@@ -570,9 +523,9 @@ public class ViewKeyActivity extends BaseNfcActivity implements
Intent intent = new Intent(
ViewKeyActivity.this, ViewKeyActivity.class);
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent);
finish();
}
@@ -586,15 +539,14 @@ public class ViewKeyActivity extends BaseNfcActivity implements
public void onAction() {
Intent intent = new Intent(
ViewKeyActivity.this, CreateKeyActivity.class);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent);
finish();
}
}, R.string.snack_yubikey_import).show();
}
-
}
public void showYubiKeyFragment(
@@ -629,7 +581,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
long keyId = new ProviderHelper(this)
.getCachedPublicKeyRing(dataUri)
.extractOrGetMasterKeyId();
- long[] encryptionKeyIds = new long[] {keyId};
+ long[] encryptionKeyIds = new long[]{keyId};
Intent intent;
if (text) {
intent = new Intent(this, EncryptTextActivity.class);
@@ -647,38 +599,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements
}
}
- private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper)
- throws ProviderHelper.NotFoundException {
-
- mIsRefreshing = true;
- mRefreshItem.setEnabled(false);
- mRefreshItem.setActionView(mRefresh);
- mRefresh.startAnimation(mRotate);
-
- byte[] blob = (byte[]) providerHelper.getGenericData(
- KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
- KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
- String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob);
-
- ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
- ArrayList<ParcelableKeyRing> entries = new ArrayList<>();
- entries.add(keyEntry);
- mKeyList = entries;
-
- // search config
- {
- Preferences prefs = Preferences.getPreferences(this);
- Preferences.CloudSearchPrefs cloudPrefs =
- new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
- mKeyserver = cloudPrefs.keyserver;
- }
-
- mOperationHelper = new CryptoOperationHelper<>(
- this, this, R.string.progress_importing);
-
- mOperationHelper.cryptoOperation();
- }
-
private void editKey(Uri dataUri) {
Intent editIntent = new Intent(this, EditKeyActivity.class);
editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri));
@@ -735,7 +655,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
// These are the rows that we will retrieve.
- static final String[] PROJECTION = new String[] {
+ static final String[] PROJECTION = new String[]{
KeychainContract.KeyRings._ID,
KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.KeyRings.USER_ID,
@@ -771,6 +691,25 @@ public class ViewKeyActivity extends BaseNfcActivity implements
int mPreviousColor = 0;
+ /**
+ * Calculate a reasonable color for the status bar based on the given toolbar color.
+ * Style guides want the toolbar color to be a "700" on the Android scale and the status
+ * bar should be the same color at "500", this is roughly 17 / 20th of the value in each
+ * channel.
+ * http://www.google.com/design/spec/style/color.html#color-color-palette
+ */
+ static public int getStatusBarBackgroundColor(int color) {
+ int r = (color >> 16) & 0xff;
+ int g = (color >> 8) & 0xff;
+ int b = color & 0xff;
+
+ r = r * 17 / 20;
+ g = g * 17 / 20;
+ b = b * 17 / 20;
+
+ return (0xff << 24) | (r << 16) | (g << 8) | b;
+ }
+
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/* TODO better error handling? May cause problems when a key is deleted,
@@ -823,7 +762,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
AsyncTask<Long, Void, Bitmap> photoTask =
new AsyncTask<Long, Void, Bitmap>() {
protected Bitmap doInBackground(Long... mMasterKeyId) {
- return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(), mMasterKeyId[0], true);
+ return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(),
+ mMasterKeyId[0], true);
}
protected void onPostExecute(Bitmap photo) {
@@ -839,7 +779,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mStatusImage.setVisibility(View.VISIBLE);
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
State.REVOKED, R.color.icons, true);
- color = getResources().getColor(R.color.android_red_light);
+ color = getResources().getColor(R.color.key_flag_red);
mActionEncryptFile.setVisibility(View.GONE);
mActionEncryptText.setVisibility(View.GONE);
@@ -855,7 +795,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mStatusImage.setVisibility(View.VISIBLE);
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
State.EXPIRED, R.color.icons, true);
- color = getResources().getColor(R.color.android_red_light);
+ color = getResources().getColor(R.color.key_flag_red);
mActionEncryptFile.setVisibility(View.GONE);
mActionEncryptText.setVisibility(View.GONE);
@@ -865,7 +805,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
} else if (mIsSecret) {
mStatusText.setText(R.string.view_key_my_key);
mStatusImage.setVisibility(View.GONE);
- color = getResources().getColor(R.color.primary);
+ color = getResources().getColor(R.color.key_flag_green);
// reload qr code only if the fingerprint changed
if (!mFingerprint.equals(mQrCodeLoaded)) {
loadQrCode(mFingerprint);
@@ -903,6 +843,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mActionNfc.setVisibility(View.GONE);
}
mFab.setVisibility(View.VISIBLE);
+ // noinspection deprecation (no getDrawable with theme at current minApi level 15!)
mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp));
} else {
mActionEncryptFile.setVisibility(View.VISIBLE);
@@ -915,7 +856,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mStatusImage.setVisibility(View.VISIBLE);
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
State.VERIFIED, R.color.icons, true);
- color = getResources().getColor(R.color.primary);
+ color = getResources().getColor(R.color.key_flag_green);
photoTask.execute(mMasterKeyId);
mFab.setVisibility(View.GONE);
@@ -924,20 +865,21 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mStatusImage.setVisibility(View.VISIBLE);
KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText,
State.UNVERIFIED, R.color.icons, true);
- color = getResources().getColor(R.color.android_orange_light);
+ color = getResources().getColor(R.color.key_flag_orange);
mFab.setVisibility(View.VISIBLE);
}
}
if (mPreviousColor == 0 || mPreviousColor == color) {
- mStatusBar.setBackgroundColor(color);
+ mStatusBar.setBackgroundColor(getStatusBarBackgroundColor(color));
mBigToolbar.setBackgroundColor(color);
mPreviousColor = color;
} else {
ObjectAnimator colorFade1 =
ObjectAnimator.ofObject(mStatusBar, "backgroundColor",
- new ArgbEvaluator(), mPreviousColor, color);
+ new ArgbEvaluator(), mPreviousColor,
+ getStatusBarBackgroundColor(color));
ObjectAnimator colorFade2 =
ObjectAnimator.ofObject(mBigToolbar, "backgroundColor",
new ArgbEvaluator(), mPreviousColor, color);
@@ -965,6 +907,36 @@ public class ViewKeyActivity extends BaseNfcActivity implements
// CryptoOperationHelper.Callback functions
+
+ private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper)
+ throws ProviderHelper.NotFoundException {
+
+ mIsRefreshing = true;
+ mRefreshItem.setEnabled(false);
+ mRefreshItem.setActionView(mRefresh);
+ mRefresh.startAnimation(mRotate);
+
+ byte[] blob = (byte[]) providerHelper.getGenericData(
+ KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
+ KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+ String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob);
+
+ ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
+ ArrayList<ParcelableKeyRing> entries = new ArrayList<>();
+ entries.add(keyEntry);
+ mKeyList = entries;
+
+ // search config
+ {
+ Preferences prefs = Preferences.getPreferences(this);
+ Preferences.CloudSearchPrefs cloudPrefs =
+ new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
+ mKeyserver = cloudPrefs.keyserver;
+ }
+
+ mOperationHelper.cryptoOperation();
+ }
+
@Override
public ImportKeyringParcel createOperationInput() {
return new ImportKeyringParcel(mKeyList, mKeyserver);
@@ -989,6 +961,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements
@Override
public boolean onCryptoSetProgress(String msg, int progress, int max) {
- return false;
+ return true;
}
-} \ No newline at end of file
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
index 6669f2654..673092e61 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
@@ -211,18 +211,18 @@ public class ViewKeyAdvActivity extends BaseActivity implements
// Note: order is important
int color;
if (isRevoked || isExpired) {
- color = getResources().getColor(R.color.android_red_light);
+ color = getResources().getColor(R.color.key_flag_red);
} else if (isSecret) {
- color = getResources().getColor(R.color.primary);
+ color = getResources().getColor(R.color.android_green_light);
} else {
if (isVerified) {
- color = getResources().getColor(R.color.primary);
+ color = getResources().getColor(R.color.android_green_light);
} else {
- color = getResources().getColor(R.color.android_orange_light);
+ color = getResources().getColor(R.color.key_flag_orange);
}
}
mToolbar.setBackgroundColor(color);
- mStatusBar.setBackgroundColor(color);
+ mStatusBar.setBackgroundColor(ViewKeyActivity.getStatusBarBackgroundColor(color));
mSlidingTabLayout.setBackgroundColor(color);
break;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
index b44e6dc78..4a46896bc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
@@ -25,6 +25,9 @@ import java.io.OutputStreamWriter;
import android.app.Activity;
import android.app.ActivityOptions;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -49,16 +52,18 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+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.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
+import org.sufficientlysecure.keychain.util.ExportHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.NfcHelper;
@@ -79,6 +84,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
private Uri mDataUri;
private byte[] mFingerprint;
+ private long mMasterKeyId;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
@@ -101,11 +107,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
View vFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
View vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
View vKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
+ View vKeySafeButton = view.findViewById(R.id.view_key_action_key_export);
View vKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);
View vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
ImageButton vKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
View vKeyUploadButton = view.findViewById(R.id.view_key_action_upload);
- vKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
+ vKeySafeSlingerButton.setColorFilter(FormattingUtils.getColorFromAttr(getActivity(), R.attr.colorTertiaryText),
PorterDuff.Mode.SRC_IN);
vFingerprintShareButton.setOnClickListener(new View.OnClickListener() {
@@ -126,6 +133,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
share(false, false);
}
});
+ vKeySafeButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ exportToFile();
+ }
+ });
vKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -161,6 +174,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
return root;
}
+ private void exportToFile() {
+ new ExportHelper(getActivity()).showExportKeysDialog(
+ mMasterKeyId, Constants.Path.APP_DIR_FILE, false);
+ }
+
private void startSafeSlinger(Uri dataUri) {
long keyId = 0;
try {
@@ -197,7 +215,15 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
}
if (toClipboard) {
- ClipboardReflection.copyToClipboard(activity, content);
+ ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipMan == null) {
+ Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR);
+ return;
+ }
+
+ ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, content);
+ clipMan.setPrimaryClip(clip);
+
Notify.create(activity, fingerprintOnly ? R.string.fingerprint_copied_to_clipboard
: R.string.key_copied_to_clipboard, Notify.Style.OK).show();
return;
@@ -344,6 +370,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
/** Load QR Code asynchronously and with a fade in animation */
private void setFingerprint(byte[] fingerprintBlob) {
mFingerprint = fingerprintBlob;
+ mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(fingerprintBlob);
final String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob);
mFingerprintView.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint));
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java
index 092ab40d6..b118c3ad0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java
@@ -51,6 +51,9 @@ import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
+import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
import java.util.ArrayList;
import java.util.Hashtable;
@@ -197,8 +200,22 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
mStartSearch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- mStartSearch.setEnabled(false);
- new DescribeKey().execute(fingerprint);
+ final Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(getActivity())
+ .getProxyPrefs();
+
+ Runnable ignoreTor = new Runnable() {
+ @Override
+ public void run() {
+ mStartSearch.setEnabled(false);
+ new DescribeKey(proxyPrefs.parcelableProxy).execute(fingerprint);
+ }
+ };
+
+ if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, proxyPrefs,
+ getActivity())) {
+ mStartSearch.setEnabled(false);
+ new DescribeKey(proxyPrefs.parcelableProxy).execute(fingerprint);
+ }
}
});
}
@@ -229,6 +246,11 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
// look for evidence from keybase in the background, make tabular version of result
//
private class DescribeKey extends AsyncTask<String, Void, ResultPage> {
+ ParcelableProxy mParcelableProxy;
+
+ public DescribeKey(ParcelableProxy parcelableProxy) {
+ mParcelableProxy = parcelableProxy;
+ }
@Override
protected ResultPage doInBackground(String... args) {
@@ -237,7 +259,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
final ArrayList<CharSequence> proofList = new ArrayList<CharSequence>();
final Hashtable<Integer, ArrayList<Proof>> proofs = new Hashtable<Integer, ArrayList<Proof>>();
try {
- User keybaseUser = User.findByFingerprint(fingerprint);
+ User keybaseUser = User.findByFingerprint(fingerprint, mParcelableProxy.getProxy());
for (Proof proof : keybaseUser.getProofs()) {
Integer proofType = proof.getType();
appendIfOK(proofs, proofType, proof);
@@ -376,7 +398,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
mProofVerifyDetail.setVisibility(View.GONE);
- mKeybaseOpHelper = new CryptoOperationHelper<>(this, this,
+ mKeybaseOpHelper = new CryptoOperationHelper<>(1, this, this,
R.string.progress_verifying_signature);
mKeybaseOpHelper.cryptoOperation();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java
index f8c3b59ea..f980f297b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
+
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -39,12 +40,12 @@ import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
public class ViewKeyYubiKeyFragment
- extends CryptoOperationFragment<PromoteKeyringParcel, PromoteKeyResult>
+ extends QueueingCryptoOperationFragment<PromoteKeyringParcel, PromoteKeyResult>
implements LoaderCallbacks<Cursor> {
public static final String ARG_MASTER_KEY_ID = "master_key_id";
@@ -75,6 +76,10 @@ public class ViewKeyYubiKeyFragment
return frag;
}
+ public ViewKeyYubiKeyFragment() {
+ super(null);
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -210,7 +215,8 @@ public class ViewKeyYubiKeyFragment
}
@Override
- protected void onCryptoOperationResult(PromoteKeyResult result) {
+ public void onQueuedOperationSuccess(PromoteKeyResult result) {
result.createNotify(getActivity()).show();
}
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
index 93c6593ab..0be7e8f76 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
@@ -177,9 +177,9 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
}
if (entry.isRevoked()) {
- KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, State.REVOKED, R.color.bg_gray);
+ KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, State.REVOKED, R.color.key_flag_gray);
} else if (entry.isExpired()) {
- KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, State.EXPIRED, R.color.bg_gray);
+ KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, State.EXPIRED, R.color.key_flag_gray);
}
if (entry.isRevoked() || entry.isExpired()) {
@@ -188,9 +188,9 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
// no more space for algorithm display
holder.algorithm.setVisibility(View.GONE);
- holder.mainUserId.setTextColor(getContext().getResources().getColor(R.color.bg_gray));
- holder.mainUserIdRest.setTextColor(getContext().getResources().getColor(R.color.bg_gray));
- holder.keyId.setTextColor(getContext().getResources().getColor(R.color.bg_gray));
+ holder.mainUserId.setTextColor(getContext().getResources().getColor(R.color.key_flag_gray));
+ holder.mainUserIdRest.setTextColor(getContext().getResources().getColor(R.color.key_flag_gray));
+ holder.keyId.setTextColor(getContext().getResources().getColor(R.color.key_flag_gray));
} else {
holder.status.setVisibility(View.GONE);
holder.algorithm.setVisibility(View.VISIBLE);
@@ -198,11 +198,11 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
if (entry.isSecretKey()) {
holder.mainUserId.setTextColor(Color.RED);
} else {
- holder.mainUserId.setTextColor(Color.BLACK);
+ holder.mainUserId.setTextColor(FormattingUtils.getColorFromAttr(mActivity, R.attr.colorText));
}
- holder.mainUserIdRest.setTextColor(Color.BLACK);
- holder.keyId.setTextColor(Color.BLACK);
+ holder.mainUserIdRest.setTextColor(FormattingUtils.getColorFromAttr(mActivity, R.attr.colorText));
+ holder.keyId.setTextColor(FormattingUtils.getColorFromAttr(mActivity, R.attr.colorText));
}
if (entry.getUserIds().size() == 1) {
@@ -242,9 +242,9 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
uidView.setPadding(0, 0, FormattingUtils.dpToPx(getContext(), 8), 0);
if (entry.isRevoked() || entry.isExpired()) {
- uidView.setTextColor(getContext().getResources().getColor(R.color.bg_gray));
+ uidView.setTextColor(getContext().getResources().getColor(R.color.key_flag_gray));
} else {
- uidView.setTextColor(getContext().getResources().getColor(R.color.black));
+ uidView.setTextColor(FormattingUtils.getColorFromAttr(getContext(), R.attr.colorText));
}
holder.userIdsList.addView(uidView);
@@ -258,9 +258,9 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
emailView.setText(highlighter.highlight(email));
if (entry.isRevoked() || entry.isExpired()) {
- emailView.setTextColor(getContext().getResources().getColor(R.color.bg_gray));
+ emailView.setTextColor(getContext().getResources().getColor(R.color.key_flag_gray));
} else {
- emailView.setTextColor(getContext().getResources().getColor(R.color.black));
+ emailView.setTextColor(FormattingUtils.getColorFromAttr(getContext(), R.attr.colorText));
}
holder.userIdsList.addView(emailView);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java
index af919f3b6..e77c92923 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context;
+import android.support.annotation.Nullable;
import android.support.v4.content.AsyncTaskLoader;
import org.sufficientlysecure.keychain.Constants;
@@ -26,8 +27,12 @@ import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.Keyserver;
import org.sufficientlysecure.keychain.operations.results.GetKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
import java.util.ArrayList;
@@ -38,15 +43,27 @@ public class ImportKeysListCloudLoader
Preferences.CloudSearchPrefs mCloudPrefs;
String mServerQuery;
+ private ParcelableProxy mParcelableProxy;
private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<>();
private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
- public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs) {
+ /**
+ * Searches a keyserver as specified in cloudPrefs, using an explicit proxy if passed
+ *
+ * @param serverQuery string to search on servers for. If is a fingerprint,
+ * will enforce fingerprint check
+ * @param cloudPrefs contains keyserver to search on, whether to search on the keyserver,
+ * and whether to search keybase.io
+ * @param parcelableProxy explicit proxy to use. If null, will retrieve from preferences
+ */
+ public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs,
+ @Nullable ParcelableProxy parcelableProxy) {
super(context);
mContext = context;
mServerQuery = serverQuery;
mCloudPrefs = cloudPrefs;
+ mParcelableProxy = parcelableProxy;
}
@Override
@@ -95,9 +112,32 @@ public class ImportKeysListCloudLoader
* Query keyserver
*/
private void queryServer(boolean enforceFingerprint) {
+ ParcelableProxy parcelableProxy;
+
+ if (mParcelableProxy == null) {
+ // no explicit proxy specified, fetch from preferences
+ if (OrbotHelper.isOrbotInRequiredState(mContext)) {
+ parcelableProxy = Preferences.getPreferences(mContext).getProxyPrefs()
+ .parcelableProxy;
+ } else {
+ // user needs to enable/install orbot
+ mEntryList.clear();
+ GetKeyResult pendingResult = new GetKeyResult(null,
+ RequiredInputParcel.createOrbotRequiredOperation(),
+ new CryptoInputParcel());
+ mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, pendingResult);
+ return;
+ }
+ } else {
+ parcelableProxy = mParcelableProxy;
+ }
+
try {
- ArrayList<ImportKeysListEntry> searchResult
- = CloudSearch.search(mServerQuery, mCloudPrefs);
+ ArrayList<ImportKeysListEntry> searchResult = CloudSearch.search(
+ mServerQuery,
+ mCloudPrefs,
+ parcelableProxy.getProxy()
+ );
mEntryList.clear();
// add result to data
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
index e545b007b..aba1eb0d8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
@@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui.adapter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -43,6 +42,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.util.Highlighter;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
@@ -50,6 +50,7 @@ public class KeyAdapter extends CursorAdapter {
protected String mQuery;
protected LayoutInflater mInflater;
+ protected Context mContext;
// These are the rows that we will retrieve.
public static final String[] PROJECTION = new String[]{
@@ -78,6 +79,7 @@ public class KeyAdapter extends CursorAdapter {
public KeyAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
+ mContext = context;
mInflater = LayoutInflater.from(context);
}
@@ -107,7 +109,7 @@ public class KeyAdapter extends CursorAdapter {
mCreationDate = (TextView) view.findViewById(R.id.key_list_item_creation);
}
- public void setData(Context context, KeyItem item, Highlighter highlighter) {
+ public void setData(Context context, KeyItem item, Highlighter highlighter, boolean enabled) {
mDisplayedItem = item;
@@ -126,36 +128,39 @@ public class KeyAdapter extends CursorAdapter {
}
}
+ // sort of a hack: if this item isn't enabled, we make it clickable
+ // to intercept its click events
+ mView.setClickable(!enabled);
+
{ // set edit button and status, specific by key type
mMasterKeyId = item.mKeyId;
+ int textColor;
+
// Note: order is important!
if (item.mIsRevoked) {
KeyFormattingUtils
- .setStatusImage(context, mStatus, null, State.REVOKED, R.color.bg_gray);
+ .setStatusImage(context, mStatus, null, State.REVOKED, R.color.key_flag_gray);
mStatus.setVisibility(View.VISIBLE);
mSlinger.setVisibility(View.GONE);
- mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
- mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
+ textColor = context.getResources().getColor(R.color.key_flag_gray);
} else if (item.mIsExpired) {
- KeyFormattingUtils.setStatusImage(context, mStatus, null, State.EXPIRED, R.color.bg_gray);
+ KeyFormattingUtils.setStatusImage(context, mStatus, null, State.EXPIRED, R.color.key_flag_gray);
mStatus.setVisibility(View.VISIBLE);
mSlinger.setVisibility(View.GONE);
- mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
- mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
+ textColor = context.getResources().getColor(R.color.key_flag_gray);
} else if (item.mIsSecret) {
mStatus.setVisibility(View.GONE);
if (mSlingerButton.hasOnClickListeners()) {
mSlingerButton.setColorFilter(
- context.getResources().getColor(R.color.tertiary_text_light),
+ FormattingUtils.getColorFromAttr(context, R.attr.colorTertiaryText),
PorterDuff.Mode.SRC_IN);
mSlinger.setVisibility(View.VISIBLE);
} else {
mSlinger.setVisibility(View.GONE);
}
- mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
- mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
+ textColor = FormattingUtils.getColorFromAttr(context, R.attr.colorText);
} else {
// this is a public key - show if it's verified
if (item.mIsVerified) {
@@ -166,10 +171,16 @@ public class KeyAdapter extends CursorAdapter {
mStatus.setVisibility(View.VISIBLE);
}
mSlinger.setVisibility(View.GONE);
- mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
- mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
+ textColor = FormattingUtils.getColorFromAttr(context, R.attr.colorText);
+ }
+
+ if (!enabled) {
+ textColor = context.getResources().getColor(R.color.key_flag_gray);
}
+ mMainUserId.setTextColor(textColor);
+ mMainUserIdRest.setTextColor(textColor);
+
if (item.mHasDuplicate) {
String dateTime = DateUtils.formatDateTime(context,
item.mCreation.getTime(),
@@ -179,6 +190,7 @@ public class KeyAdapter extends CursorAdapter {
mCreationDate.setText(context.getString(R.string.label_key_created,
dateTime));
+ mCreationDate.setTextColor(textColor);
mCreationDate.setVisibility(View.VISIBLE);
} else {
mCreationDate.setVisibility(View.GONE);
@@ -205,9 +217,11 @@ public class KeyAdapter extends CursorAdapter {
@Override
public void bindView(View view, Context context, Cursor cursor) {
Highlighter highlighter = new Highlighter(context, mQuery);
- KeyItemViewHolder h = (KeyItemViewHolder) view.getTag();
KeyItem item = new KeyItem(cursor);
- h.setData(context, item, highlighter);
+ boolean isEnabled = isEnabled(cursor);
+
+ KeyItemViewHolder h = (KeyItemViewHolder) view.getTag();
+ h.setData(context, item, highlighter, isEnabled);
}
public boolean isSecretAvailable(int id) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
index a6cb52977..4ea651bb5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
@@ -149,11 +149,11 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter {
boolean enabled;
if (cursor.getInt(mIndexIsRevoked) != 0) {
h.statusIcon.setVisibility(View.VISIBLE);
- KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, State.REVOKED, R.color.bg_gray);
+ KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, State.REVOKED, R.color.key_flag_gray);
enabled = false;
} else if (cursor.getInt(mIndexIsExpiry) != 0) {
h.statusIcon.setVisibility(View.VISIBLE);
- KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, State.EXPIRED, R.color.bg_gray);
+ KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, State.EXPIRED, R.color.key_flag_gray);
enabled = false;
} else {
h.statusIcon.setVisibility(View.GONE);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index 87539ea05..24f5f04a1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -284,27 +284,27 @@ public class SubkeysAdapter extends CursorAdapter {
vStatus.setVisibility(View.VISIBLE);
vCertifyIcon.setColorFilter(
- mContext.getResources().getColor(R.color.bg_gray),
+ mContext.getResources().getColor(R.color.key_flag_gray),
PorterDuff.Mode.SRC_IN);
vSignIcon.setColorFilter(
- mContext.getResources().getColor(R.color.bg_gray),
+ mContext.getResources().getColor(R.color.key_flag_gray),
PorterDuff.Mode.SRC_IN);
vEncryptIcon.setColorFilter(
- mContext.getResources().getColor(R.color.bg_gray),
+ mContext.getResources().getColor(R.color.key_flag_gray),
PorterDuff.Mode.SRC_IN);
vAuthenticateIcon.setColorFilter(
- mContext.getResources().getColor(R.color.bg_gray),
+ mContext.getResources().getColor(R.color.key_flag_gray),
PorterDuff.Mode.SRC_IN);
if (isRevoked) {
vStatus.setImageResource(R.drawable.status_signature_revoked_cutout_24dp);
vStatus.setColorFilter(
- mContext.getResources().getColor(R.color.bg_gray),
+ mContext.getResources().getColor(R.color.key_flag_gray),
PorterDuff.Mode.SRC_IN);
} else if (isExpired) {
vStatus.setImageResource(R.drawable.status_signature_expired_cutout_24dp);
vStatus.setColorFilter(
- mContext.getResources().getColor(R.color.bg_gray),
+ mContext.getResources().getColor(R.color.key_flag_gray),
PorterDuff.Mode.SRC_IN);
}
} else {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
index d1103ac1f..e2c6b0928 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
@@ -128,7 +128,7 @@ public class UserIdsAdapter extends UserAttributesAdapter {
if (isRevoked) {
// set revocation icon (can this even be primary?)
- KeyFormattingUtils.setStatusImage(mContext, vVerified, null, State.REVOKED, R.color.bg_gray);
+ KeyFormattingUtils.setStatusImage(mContext, vVerified, null, State.REVOKED, R.color.key_flag_gray);
// disable revoked user ids
vName.setEnabled(false);
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 847d76f30..66b784f9b 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
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui.base;
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
@@ -29,6 +30,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
/**
* Setups Toolbar
@@ -36,14 +38,28 @@ import org.sufficientlysecure.keychain.R;
public abstract class BaseActivity extends AppCompatActivity {
protected Toolbar mToolbar;
protected View mStatusBar;
+ protected ThemeChanger mThemeChanger;
@Override
protected void onCreate(Bundle savedInstanceState) {
+ mThemeChanger = new ThemeChanger(this);
+ mThemeChanger.changeTheme();
super.onCreate(savedInstanceState);
initLayout();
initToolbar();
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (mThemeChanger.changeTheme()) {
+ Intent intent = getIntent();
+ finish();
+ startActivity(intent);
+ }
+ }
+
protected void initLayout() {
}
@@ -87,9 +103,7 @@ public abstract class BaseActivity extends AppCompatActivity {
mToolbar.setNavigationOnClickListener(cancelOnClickListener);
}
- /**
- * Close button only
- */
+ /** Close button only */
protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener, boolean white) {
if (white) {
setActionBarIcon(R.drawable.ic_close_white_24dp);
@@ -104,6 +118,17 @@ public abstract class BaseActivity extends AppCompatActivity {
setFullScreenDialogClose(cancelOnClickListener, true);
}
+ /** Close button only, with finish-action and given return status, white. */
+ protected void setFullScreenDialogClose(final int result, boolean white) {
+ setFullScreenDialogClose(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setResult(result);
+ finish();
+ }
+ }, white);
+ }
+
/**
* Inflate custom design with two buttons using drawables.
* This does not conform to the Material Design Guidelines, but we deviate here as this is used
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 bede16b2a..c472eaa4c 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
@@ -29,7 +29,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
+import android.nfc.TagLostException;
import android.nfc.tech.IsoDep;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.Toast;
@@ -63,6 +65,8 @@ public abstract class BaseNfcActivity extends BaseActivity {
public static final int REQUEST_CODE_PIN = 1;
+ public static final String EXTRA_TAG_HANDLING_ENABLED = "tag_handling_enabled";
+
protected Passphrase mPin;
protected Passphrase mAdminPin;
protected boolean mPw1ValidForMultipleSignatures;
@@ -71,13 +75,123 @@ public abstract class BaseNfcActivity extends BaseActivity {
protected boolean mPw3Validated;
private NfcAdapter mNfcAdapter;
private IsoDep mIsoDep;
+ private boolean mTagHandlingEnabled;
private static final int TIMEOUT = 100000;
+ private byte[] mNfcFingerprints;
+ private String mNfcUserId;
+ private byte[] mNfcAid;
+
+ /**
+ * Override to change UI before NFC handling (UI thread)
+ */
+ protected void onNfcPreExecute() {
+ }
+
+ /**
+ * Override to implement NFC operations (background thread)
+ */
+ protected void doNfcInBackground() throws IOException {
+ mNfcFingerprints = nfcGetFingerprints();
+ mNfcUserId = nfcGetUserId();
+ mNfcAid = nfcGetAid();
+ }
+
+ /**
+ * Override to handle result of NFC operations (UI thread)
+ */
+ protected void onNfcPostExecute() throws IOException {
+
+ final long subKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
+
+ try {
+ CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId));
+ long masterKeyId = ring.getMasterKeyId();
+
+ Intent intent = new Intent(this, ViewKeyActivity.class);
+ intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
+ intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
+ startActivity(intent);
+ } catch (PgpKeyNotFoundException e) {
+ Intent intent = new Intent(this, CreateKeyActivity.class);
+ intent.putExtra(CreateKeyActivity.EXTRA_NFC_AID, mNfcAid);
+ intent.putExtra(CreateKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
+ intent.putExtra(CreateKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
+ startActivity(intent);
+ }
+ }
+
+ /**
+ * Override to use something different than Notify (UI thread)
+ */
+ protected void onNfcError(String error) {
+ Notify.create(this, error, Style.WARN).show();
+ }
+
+ public void handleIntentInBackground(final Intent intent) {
+ // Actual NFC operations are executed in doInBackground to not block the UI thread
+ new AsyncTask<Void, Void, Exception>() {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ onNfcPreExecute();
+ }
+
+ @Override
+ protected Exception doInBackground(Void... params) {
+ try {
+ handleTagDiscoveredIntent(intent);
+ } catch (CardException e) {
+ return e;
+ } catch (IOException e) {
+ return e;
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Exception exception) {
+ super.onPostExecute(exception);
+
+ if (exception != null) {
+ handleNfcError(exception);
+ return;
+ }
+
+ try {
+ onNfcPostExecute();
+ } catch (IOException e) {
+ handleNfcError(e);
+ }
+ }
+ }.execute();
+ }
+
+ protected void pauseTagHandling() {
+ mTagHandlingEnabled = false;
+ }
+
+ protected void resumeTagHandling() {
+ mTagHandlingEnabled = true;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // Check whether we're recreating a previously destroyed instance
+ if (savedInstanceState != null) {
+ // Restore value of members from saved state
+ mTagHandlingEnabled = savedInstanceState.getBoolean(EXTRA_TAG_HANDLING_ENABLED);
+ } else {
+ mTagHandlingEnabled = true;
+ }
+
Intent intent = getIntent();
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) {
@@ -86,36 +200,43 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ outState.putBoolean(EXTRA_TAG_HANDLING_ENABLED, mTagHandlingEnabled);
+ }
+
/**
* This activity is started as a singleTop activity.
* All new NFC Intents which are delivered to this activity are handled here
*/
@Override
- public void onNewIntent(Intent intent) {
- if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
- try {
- handleTagDiscoveredIntent(intent);
- } catch (CardException e) {
- handleNfcError(e);
- } catch (IOException e) {
- handleNfcError(e);
- }
+ public void onNewIntent(final Intent intent) {
+ if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())
+ && mTagHandlingEnabled) {
+ handleIntentInBackground(intent);
}
}
- public void handleNfcError(IOException e) {
-
+ private void handleNfcError(Exception e) {
Log.e(Constants.TAG, "nfc error", e);
- Notify.create(this, getString(R.string.error_nfc, e.getMessage()), Style.WARN).show();
- }
- public void handleNfcError(CardException e) {
- Log.e(Constants.TAG, "card error", e);
+ if (e instanceof TagLostException) {
+ onNfcError(getString(R.string.error_nfc_tag_lost));
+ return;
+ }
- short status = e.getResponseCode();
+ short status;
+ if (e instanceof CardException) {
+ status = ((CardException) e).getResponseCode();
+ } else {
+ status = -1;
+ }
// When entering a PIN, a status of 63CX indicates X attempts remaining.
if ((status & (short)0xFFF0) == 0x63C0) {
- Notify.create(this, getString(R.string.error_pin, status & 0x000F), Style.WARN).show();
+ int tries = status & 0x000F;
+ onNfcError(getResources().getQuantityString(R.plurals.error_pin, tries, tries));
return;
}
@@ -124,63 +245,62 @@ public abstract class BaseNfcActivity extends BaseActivity {
// These errors should not occur in everyday use; if they are returned, it means we
// made a mistake sending data to the card, or the card is misbehaving.
case 0x6A80: {
- Notify.create(this, getString(R.string.error_nfc_bad_data), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_bad_data));
break;
}
case 0x6883: {
- Notify.create(this, getString(R.string.error_nfc_chaining_error), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_chaining_error));
break;
}
case 0x6B00: {
- Notify.create(this, getString(R.string.error_nfc_header, "P1/P2"), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_header, "P1/P2"));
break;
}
case 0x6D00: {
- Notify.create(this, getString(R.string.error_nfc_header, "INS"), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_header, "INS"));
break;
}
case 0x6E00: {
- Notify.create(this, getString(R.string.error_nfc_header, "CLA"), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_header, "CLA"));
break;
}
// These error conditions are more likely to be experienced by an end user.
case 0x6285: {
- Notify.create(this, getString(R.string.error_nfc_terminated), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_terminated));
break;
}
case 0x6700: {
- Notify.create(this, getString(R.string.error_nfc_wrong_length), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_wrong_length));
break;
}
case 0x6982: {
- Notify.create(this, getString(R.string.error_nfc_security_not_satisfied),
- Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_security_not_satisfied));
break;
}
case 0x6983: {
- Notify.create(this, getString(R.string.error_nfc_authentication_blocked),
- Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_authentication_blocked));
break;
}
case 0x6985: {
- Notify.create(this, getString(R.string.error_nfc_conditions_not_satisfied),
- Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_conditions_not_satisfied));
break;
}
// 6A88 is "Not Found" in the spec, but Yubikey also returns 6A83 for this in some cases.
case 0x6A88:
case 0x6A83: {
- Notify.create(this, getString(R.string.error_nfc_data_not_found), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_data_not_found));
break;
}
// 6F00 is a JavaCard proprietary status code, SW_UNKNOWN, and usually represents an
// unhandled exception on the smart card.
case 0x6F00: {
- Notify.create(this, getString(R.string.error_nfc_unknown), Style.WARN).show();
+ onNfcError(getString(R.string.error_nfc_unknown));
+ break;
+ }
+ default: {
+ onNfcError(getString(R.string.error_nfc, e.getMessage()));
break;
}
- default:
- Notify.create(this, getString(R.string.error_nfc, e.getMessage()), Style.WARN).show();
}
}
@@ -311,43 +431,12 @@ public abstract class BaseNfcActivity extends BaseActivity {
mPw1ValidatedForDecrypt = false;
mPw3Validated = false;
- // TODO: Handle non-default Admin PIN
- mAdminPin = new Passphrase("12345678");
-
- onNfcPerform();
-
- mIsoDep.close();
- mIsoDep = null;
+ doNfcInBackground();
}
- protected void onNfcPerform() throws IOException {
-
- final byte[] nfcFingerprints = nfcGetFingerprints();
- final String nfcUserId = nfcGetUserId();
- final byte[] nfcAid = nfcGetAid();
-
- final long subKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints);
-
- try {
- CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId));
- long masterKeyId = ring.getMasterKeyId();
-
- Intent intent = new Intent(this, ViewKeyActivity.class);
- intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId);
- intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints);
- startActivity(intent);
- } catch (PgpKeyNotFoundException e) {
- Intent intent = new Intent(this, CreateKeyActivity.class);
- intent.putExtra(CreateKeyActivity.EXTRA_NFC_AID, nfcAid);
- intent.putExtra(CreateKeyActivity.EXTRA_NFC_USER_ID, nfcUserId);
- intent.putExtra(CreateKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints);
- startActivity(intent);
- }
-
+ public boolean isNfcConnected() {
+ return mIsoDep.isConnected();
}
/** Return the key id from application specific data stored on tag, or null
@@ -569,12 +658,12 @@ public abstract class BaseNfcActivity extends BaseActivity {
*/
public void nfcVerifyPIN(int mode) throws IOException {
if (mPin != null || mode == 0x83) {
- byte[] pin;
+ byte[] pin;
if (mode == 0x83) {
- pin = new String(mAdminPin.getCharArray()).getBytes();
+ pin = mAdminPin.toStringUnsafe().getBytes();
} else {
- pin = new String(mPin.getCharArray()).getBytes();
+ pin = mPin.toStringUnsafe().getBytes();
}
// SW1/2 0x9000 is the generic "ok" response, which we expect most of the time.
@@ -609,14 +698,13 @@ public abstract class BaseNfcActivity extends BaseActivity {
* conformance to the card's requirements for key length.
*
* @param pw For PW1, this is 0x81. For PW3 (Admin PIN), mode is 0x83.
- * @param newPinString The new PW1 or PW3.
+ * @param newPin The new PW1 or PW3.
*/
- public void nfcModifyPIN(int pw, String newPinString) throws IOException {
+ public void nfcModifyPIN(int pw, byte[] newPin) throws IOException {
final int MAX_PW1_LENGTH_INDEX = 1;
final int MAX_PW3_LENGTH_INDEX = 3;
byte[] pwStatusBytes = nfcGetPwStatusBytes();
- byte[] newPin = newPinString.getBytes();
if (pw == 0x81) {
if (newPin.length < 6 || newPin.length > pwStatusBytes[MAX_PW1_LENGTH_INDEX]) {
@@ -631,11 +719,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
byte[] pin;
-
if (pw == 0x83) {
- pin = new String(mAdminPin.getCharArray()).getBytes();
+ pin = mAdminPin.toStringUnsafe().getBytes();
} else {
- pin = new String(mPin.getCharArray()).getBytes();
+ pin = mPin.toStringUnsafe().getBytes();
}
// Command APDU for CHANGE REFERENCE DATA command (page 32)
@@ -700,7 +787,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
throw new IOException("Invalid key slot");
}
- RSAPrivateCrtKey crtSecretKey = null;
+ RSAPrivateCrtKey crtSecretKey;
try {
secretKey.unlock(passphrase);
crtSecretKey = secretKey.getCrtSecretKey();
@@ -719,7 +806,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
if (!mPw3Validated) {
- nfcVerifyPIN(0x83); // (Verify PW1 with mode 83)
+ nfcVerifyPIN(0x83); // (Verify PW3 with mode 83)
}
byte[] header= Hex.decode(
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java
index 17e4e6ede..06361e8cb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java
@@ -8,7 +8,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;
public abstract class CachingCryptoOperationFragment <T extends Parcelable, S extends OperationResult>
- extends CryptoOperationFragment<T, S> {
+ extends QueueingCryptoOperationFragment<T, S> {
public static final String ARG_CACHED_ACTIONS = "cached_actions";
@@ -31,8 +31,12 @@ public abstract class CachingCryptoOperationFragment <T extends Parcelable, S ex
}
@Override
- protected void onCryptoOperationResult(S result) {
- super.onCryptoOperationResult(result);
+ public void onQueuedOperationSuccess(S result) {
+ mCachedActionsParcel = null;
+ }
+
+ @Override
+ public void onQueuedOperationError(S result) {
mCachedActionsParcel = null;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
index 19d808ba6..52507f3e9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
@@ -18,78 +18,112 @@
package org.sufficientlysecure.keychain.ui.base;
+import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.os.Parcelable;
+import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.service.KeychainService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
-/**
- * All fragments executing crypto operations need to extend this class.
+/** This is a base class for fragments which implement a cryptoOperation.
+ *
+ * Subclasses of this class can call the cryptoOperation method to execute an
+ * operation in KeychainService which takes a parcelable of type T as its input
+ * and returns an OperationResult of type S as a result.
+ *
+ * The input (of type T) is not given directly to the cryptoOperation method,
+ * but must be provided by the overriden createOperationInput method to be
+ * available upon request during execution of the cryptoOperation.
+ *
+ * After running cryptoOperation, one of the onCryptoOperation*() methods will
+ * be called, depending on the success status of the operation. The subclass
+ * must override at least onCryptoOperationSuccess to proceed after a
+ * successful operation.
+ *
+ * @see KeychainService
+ *
*/
-public abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
+abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
extends Fragment implements CryptoOperationHelper.Callback<T, S> {
- private CryptoOperationHelper<T, S> mOperationHelper;
-
- public CryptoOperationFragment() {
+ final private CryptoOperationHelper<T, S> mOperationHelper;
- mOperationHelper = new CryptoOperationHelper<>(this, this);
+ public CryptoOperationFragment(Integer initialProgressMsg) {
+ mOperationHelper = new CryptoOperationHelper<>(1, this, this, initialProgressMsg);
}
- public void setProgressMessageResource(int id) {
- mOperationHelper.setProgressMessageResource(id);
+ public CryptoOperationFragment() {
+ mOperationHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_processing);
}
-
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
mOperationHelper.handleActivityResult(requestCode, resultCode, data);
}
- @Override
- public abstract T createOperationInput();
-
+ /** Starts execution of the cryptographic operation.
+ *
+ * During this process, the createOperationInput() method will be called,
+ * this input will be handed to KeychainService, where it is executed in
+ * the appropriate *Operation class. If the result is a PendingInputResult,
+ * it is handled accordingly. Otherwise, it is returned in one of the
+ * onCryptoOperation* callbacks.
+ */
protected void cryptoOperation() {
- cryptoOperation(new CryptoInputParcel());
+ mOperationHelper.cryptoOperation();
}
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
- cryptoOperation(cryptoInput);
+ mOperationHelper.cryptoOperation(cryptoInput);
}
- protected void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) {
- mOperationHelper.cryptoOperation(cryptoInput, showProgress);
- }
+ @Override @Nullable
+ /** Creates input for the crypto operation. Called internally after the
+ * crypto operation is started by a call to cryptoOperation(). Silently
+ * cancels operation if this method returns null. */
+ public abstract T createOperationInput();
+ /** Returns false, indicating that we did not handle progress ourselves. */
public boolean onCryptoSetProgress(String msg, int progress, int max) {
return false;
}
- @Override
- public void onCryptoOperationError(S result) {
- onCryptoOperationResult(result);
- result.createNotify(getActivity()).show();
+ public void setProgressMessageResource(int id) {
+ mOperationHelper.setProgressMessageResource(id);
}
@Override
- public void onCryptoOperationCancelled() {
- }
+ /** Called when the cryptoOperation() was successful. No default behavior
+ * here, this should always be implemented by a subclass! */
+ abstract public void onCryptoOperationSuccess(S result);
@Override
- public void onCryptoOperationSuccess(S result) {
- onCryptoOperationResult(result);
+ abstract public void onCryptoOperationError(S result);
+
+ @Override
+ public void onCryptoOperationCancelled() {
}
- /**
- *
- * To be overriden by subclasses, if desired. Provides a way to access the method by the
- * same name in CryptoOperationHelper, if super.onCryptoOperationSuccess and
- * super.onCryptoOperationError are called at the start of the respective functions in the
- * subclass overriding them
- * @param result
- */
- protected void onCryptoOperationResult(S result) {
+ public 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);
}
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
index 240dd0972..b33128978 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
@@ -28,10 +28,9 @@ import android.os.Messenger;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
-
import android.support.v4.app.FragmentManager;
+
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.KeychainService;
@@ -39,7 +38,9 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.NfcOperationActivity;
+import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity;
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
+import org.sufficientlysecure.keychain.ui.RetryUploadDialogActivity;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
@@ -52,23 +53,33 @@ import org.sufficientlysecure.keychain.util.Log;
*/
public class CryptoOperationHelper<T extends Parcelable, S extends OperationResult> {
- public interface Callback <T extends Parcelable, S extends OperationResult> {
+ public interface Callback<T extends Parcelable, S extends OperationResult> {
T createOperationInput();
+
void onCryptoOperationSuccess(S result);
+
void onCryptoOperationCancelled();
+
void onCryptoOperationError(S result);
+
boolean onCryptoSetProgress(String msg, int progress, int max);
}
- public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
- public static final int REQUEST_CODE_NFC = 0x00008002;
+ // request codes from CryptoOperationHelper are created essentially
+ // a static property, used to identify requestCodes meant for this
+ // particular helper. a request code looks as follows:
+ // (id << 9) + (1<<8) + REQUEST_CODE_X
+ // that is, starting from LSB, there are 8 bits request code, 1
+ // fixed bit set, then 7 bit operator-id code. the first two
+ // summands are stored in the mId for easy operation.
+ private final int mId;
- // keeps track of request code used to start an activity from this CryptoOperationHelper.
- // this is necessary when multiple CryptoOperationHelpers are used in the same fragment/activity
- // otherwise all CryptoOperationHandlers may respond to the same onActivityResult
- private int mRequestedCode = -1;
+ public static final int REQUEST_CODE_PASSPHRASE = 1;
+ public static final int REQUEST_CODE_NFC = 2;
+ public static final int REQUEST_CODE_ENABLE_ORBOT = 3;
+ public static final int REQUEST_CODE_RETRY_UPLOAD = 4;
- private int mProgressMessageResource;
+ private Integer mProgressMessageResource;
private FragmentActivity mActivity;
private Fragment mFragment;
@@ -78,10 +89,10 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
/**
* If OperationHelper is being integrated into an activity
- *
- * @param activity
*/
- public CryptoOperationHelper(FragmentActivity activity, Callback<T, S> callback, int progressMessageString) {
+ public CryptoOperationHelper(int id, FragmentActivity activity, Callback<T, S> callback,
+ Integer progressMessageString) {
+ mId = (id << 9) + (1<<8);
mActivity = activity;
mUseFragment = false;
mCallback = callback;
@@ -90,48 +101,33 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
/**
* if OperationHelper is being integrated into a fragment
- *
- * @param fragment
*/
- public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback, int progressMessageString) {
+ public CryptoOperationHelper(int id, Fragment fragment, Callback<T, S> callback, Integer progressMessageString) {
+ mId = (id << 9) + (1<<8);
mFragment = fragment;
mUseFragment = true;
mProgressMessageResource = progressMessageString;
mCallback = callback;
}
- /**
- * if OperationHelper is being integrated into a fragment with default message for the progress dialog
- *
- * @param fragment
- */
- public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback) {
- mFragment = fragment;
- mUseFragment = true;
- mProgressMessageResource = R.string.progress_building_key;
- mCallback = callback;
- }
-
public void setProgressMessageResource(int id) {
mProgressMessageResource = id;
}
- private void initiateInputActivity(RequiredInputParcel requiredInput) {
+ private void initiateInputActivity(RequiredInputParcel requiredInput,
+ CryptoInputParcel cryptoInputParcel) {
Activity activity = mUseFragment ? mFragment.getActivity() : mActivity;
switch (requiredInput.mType) {
+ // always use CryptoOperationHelper.startActivityForResult!
case NFC_MOVE_KEY_TO_CARD:
case NFC_DECRYPT:
case NFC_SIGN: {
Intent intent = new Intent(activity, NfcOperationActivity.class);
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
- mRequestedCode = REQUEST_CODE_NFC;
- if (mUseFragment) {
- mFragment.startActivityForResult(intent, mRequestedCode);
- } else {
- mActivity.startActivityForResult(intent, mRequestedCode);
- }
+ intent.putExtra(NfcOperationActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel);
+ startActivityForResult(intent, REQUEST_CODE_NFC);
return;
}
@@ -139,37 +135,55 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
case PASSPHRASE_SYMMETRIC: {
Intent intent = new Intent(activity, PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
- mRequestedCode = REQUEST_CODE_PASSPHRASE;
- if (mUseFragment) {
- mFragment.startActivityForResult(intent, mRequestedCode);
- } else {
- mActivity.startActivityForResult(intent, mRequestedCode);
- }
+ intent.putExtra(PassphraseDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel);
+ startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
return;
}
+
+ case ENABLE_ORBOT: {
+ Intent intent = new Intent(activity, OrbotRequiredDialogActivity.class);
+ intent.putExtra(OrbotRequiredDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel);
+ startActivityForResult(intent, REQUEST_CODE_ENABLE_ORBOT);
+ return;
+ }
+
+ case UPLOAD_FAIL_RETRY: {
+ Intent intent = new Intent(activity, RetryUploadDialogActivity.class);
+ intent.putExtra(RetryUploadDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel);
+ startActivityForResult(intent, REQUEST_CODE_RETRY_UPLOAD);
+ return;
+ }
+
+ default: {
+ throw new RuntimeException("Unhandled pending result!");
+ }
}
+ }
- throw new RuntimeException("Unhandled pending result!");
+ protected void startActivityForResult(Intent intent, int requestCode) {
+ if (mUseFragment) {
+ mFragment.startActivityForResult(intent, mId + requestCode);
+ } else {
+ mActivity.startActivityForResult(intent, mId + requestCode);
+ }
}
/**
- * Attempts the result of an activity started by this helper. Returns true if requestCode is recognized,
- * false otherwise.
- *
- * @param requestCode
- * @param resultCode
- * @param data
+ * Attempts the result of an activity started by this helper. Returns true if requestCode is
+ * recognized, false otherwise.
* @return true if requestCode was recognized, false otherwise
*/
public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(Constants.TAG, "received activity result in OperationHelper");
- if (mRequestedCode != requestCode) {
+ if ((requestCode & mId) != mId) {
// this wasn't meant for us to handle
return false;
- } else {
- mRequestedCode = -1;
}
+ Log.d(Constants.TAG, "handling activity result in OperationHelper");
+ // filter out mId from requestCode
+ requestCode ^= mId;
+
if (resultCode == Activity.RESULT_CANCELED) {
mCallback.onCryptoOperationCancelled();
return true;
@@ -181,7 +195,6 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
CryptoInputParcel cryptoInput =
data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT);
cryptoOperation(cryptoInput);
- return true;
}
break;
}
@@ -189,17 +202,33 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
case REQUEST_CODE_NFC: {
if (resultCode == Activity.RESULT_OK && data != null) {
CryptoInputParcel cryptoInput =
- data.getParcelableExtra(NfcOperationActivity.RESULT_DATA);
+ data.getParcelableExtra(NfcOperationActivity.RESULT_CRYPTO_INPUT);
cryptoOperation(cryptoInput);
- return true;
}
break;
}
- default: {
- return false;
+ case REQUEST_CODE_ENABLE_ORBOT: {
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ CryptoInputParcel cryptoInput =
+ data.getParcelableExtra(
+ OrbotRequiredDialogActivity.RESULT_CRYPTO_INPUT);
+ cryptoOperation(cryptoInput);
+ }
+ break;
+ }
+
+ case REQUEST_CODE_RETRY_UPLOAD: {
+ if (resultCode == Activity.RESULT_OK) {
+ CryptoInputParcel cryptoInput =
+ data.getParcelableExtra(
+ RetryUploadDialogActivity.RESULT_CRYPTO_INPUT);
+ cryptoOperation(cryptoInput);
+ }
+ break;
}
}
+
return true;
}
@@ -225,7 +254,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
}
- public void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) {
+ public void cryptoOperation(final CryptoInputParcel cryptoInput) {
FragmentActivity activity = mUseFragment ? mFragment.getActivity() : mActivity;
@@ -264,7 +293,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
@Override
protected void onSetProgress(String msg, int progress, int max) {
// allow handling of progress in fragment, or delegate upwards
- if ( ! mCallback.onCryptoSetProgress(msg, progress, max)) {
+ if (!mCallback.onCryptoSetProgress(msg, progress, max)) {
super.onSetProgress(msg, progress, max);
}
}
@@ -274,7 +303,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
- if (showProgress) {
+ if (mProgressMessageResource != null) {
saveHandler.showProgressDialog(
activity.getString(mProgressMessageResource),
ProgressDialog.STYLE_HORIZONTAL, false);
@@ -283,31 +312,18 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
activity.startService(intent);
}
- public void cryptoOperation(CryptoInputParcel cryptoInputParcel) {
- cryptoOperation(cryptoInputParcel, true);
- }
-
public void cryptoOperation() {
cryptoOperation(new CryptoInputParcel());
}
- protected void onCryptoOperationResult(S result) {
- if (result.success()) {
- mCallback.onCryptoOperationSuccess(result);
- } else {
- mCallback.onCryptoOperationError(result);
- }
- }
-
public void onHandleResult(OperationResult result) {
Log.d(Constants.TAG, "Handling result in OperationHelper success: " + result.success());
if (result instanceof InputPendingResult) {
InputPendingResult pendingResult = (InputPendingResult) result;
if (pendingResult.isPending()) {
-
RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
- initiateInputActivity(requiredInput);
+ initiateInputActivity(requiredInput, pendingResult.mCryptoInputParcel);
return;
}
}
@@ -315,12 +331,16 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
dismissProgress();
try {
- // noinspection unchecked, because type erasure :(
- onCryptoOperationResult((S) result);
+ if (result.success()) {
+ // noinspection unchecked, because type erasure :(
+ mCallback.onCryptoOperationSuccess((S) result);
+ } else {
+ // noinspection unchecked, because type erasure :(
+ mCallback.onCryptoOperationError((S) result);
+ }
} catch (ClassCastException e) {
throw new AssertionError("bad return class ("
+ result.getClass().getSimpleName() + "), this is a programming error!");
}
-
}
} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java
new file mode 100644
index 000000000..65e0ce941
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java
@@ -0,0 +1,93 @@
+package org.sufficientlysecure.keychain.ui.base;
+
+
+import android.os.Bundle;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.operations.results.OperationResult;
+
+
+/** CryptoOperationFragment which calls crypto operation results only while
+ * attached to Activity.
+ *
+ * This subclass of CryptoOperationFragment substitutes the onCryptoOperation*
+ * methods for onQueuedOperation* ones, which are ensured to be called while
+ * the fragment is attached to an Activity, possibly delaying the call until
+ * the Fragment is re-attached.
+ *
+ * TODO merge this functionality into CryptoOperationFragment?
+ *
+ * @see CryptoOperationFragment
+ */
+public abstract class QueueingCryptoOperationFragment<T extends Parcelable, S extends OperationResult>
+ extends CryptoOperationFragment<T,S> {
+
+ public static final String ARG_QUEUED_RESULT = "queued_result";
+ private S mQueuedResult;
+
+ public QueueingCryptoOperationFragment() {
+ super();
+ }
+
+ public QueueingCryptoOperationFragment(Integer initialProgressMsg) {
+ super(initialProgressMsg);
+ }
+
+ @Override
+ public void onViewStateRestored(Bundle savedInstanceState) {
+ super.onViewStateRestored(savedInstanceState);
+
+ if (mQueuedResult != null) {
+ try {
+ if (mQueuedResult.success()) {
+ onQueuedOperationSuccess(mQueuedResult);
+ } else {
+ onQueuedOperationError(mQueuedResult);
+ }
+ } finally {
+ mQueuedResult = null;
+ }
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ outState.putParcelable(ARG_QUEUED_RESULT, mQueuedResult);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ mQueuedResult = savedInstanceState.getParcelable(ARG_QUEUED_RESULT);
+ }
+ }
+
+ public abstract void onQueuedOperationSuccess(S result);
+
+ public void onQueuedOperationError(S result) {
+ hideKeyboard();
+ result.createNotify(getActivity()).show();
+ }
+
+ @Override
+ final public void onCryptoOperationSuccess(S result) {
+ if (getActivity() == null) {
+ mQueuedResult = result;
+ return;
+ }
+ onQueuedOperationSuccess(result);
+ }
+
+ @Override
+ final public void onCryptoOperationError(S result) {
+ if (getActivity() == null) {
+ mQueuedResult = result;
+ return;
+ }
+ onQueuedOperationError(result);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java
index 2c1714b67..691cc009d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java
@@ -24,7 +24,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import android.app.Activity;
-import android.app.AlertDialog;
+import android.support.v7.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
@@ -48,13 +48,23 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.TlsHelper;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
-public class AddKeyserverDialogFragment extends DialogFragment implements OnEditorActionListener {
- private static final String ARG_MESSENGER = "messenger";
+import java.net.Proxy;
+
+public class AddEditKeyserverDialogFragment extends DialogFragment implements OnEditorActionListener {
+ private static final String ARG_MESSENGER = "arg_messenger";
+ private static final String ARG_ACTION = "arg_dialog_action";
+ private static final String ARG_POSITION = "arg_position";
+ private static final String ARG_KEYSERVER = "arg_keyserver";
public static final int MESSAGE_OKAY = 1;
public static final int MESSAGE_VERIFICATION_FAILED = 2;
@@ -62,20 +72,37 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
public static final String MESSAGE_KEYSERVER = "new_keyserver";
public static final String MESSAGE_VERIFIED = "verified";
public static final String MESSAGE_FAILURE_REASON = "failure_reason";
+ public static final String MESSAGE_KEYSERVER_DELETED = "keyserver_deleted";
+ public static final String MESSAGE_DIALOG_ACTION = "message_dialog_action";
+ public static final String MESSAGE_EDIT_POSITION = "keyserver_edited_position";
private Messenger mMessenger;
+ private DialogAction mDialogAction;
+ private int mPosition;
+
private EditText mKeyserverEditText;
private CheckBox mVerifyKeyserverCheckBox;
+ public enum DialogAction {
+ ADD,
+ EDIT
+ }
+
public enum FailureReason {
INVALID_URL,
CONNECTION_FAILED
}
- public static AddKeyserverDialogFragment newInstance(Messenger messenger) {
- AddKeyserverDialogFragment frag = new AddKeyserverDialogFragment();
+ public static AddEditKeyserverDialogFragment newInstance(Messenger messenger,
+ DialogAction action,
+ String keyserver,
+ int position) {
+ AddEditKeyserverDialogFragment frag = new AddEditKeyserverDialogFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_MESSENGER, messenger);
+ args.putSerializable(ARG_ACTION, action);
+ args.putString(ARG_KEYSERVER, keyserver);
+ args.putInt(ARG_POSITION, position);
frag.setArguments(args);
@@ -88,11 +115,11 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
final Activity activity = getActivity();
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
+ mDialogAction = (DialogAction) getArguments().getSerializable(ARG_ACTION);
+ mPosition = getArguments().getInt(ARG_POSITION);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
- alert.setTitle(R.string.add_keyserver_dialog_title);
-
LayoutInflater inflater = activity.getLayoutInflater();
View view = inflater.inflate(R.layout.add_keyserver_dialog, null);
alert.setView(view);
@@ -100,14 +127,26 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
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
+ switch (mDialogAction) {
+ case ADD: {
+ alert.setTitle(R.string.add_keyserver_dialog_title);
+ break;
+ }
+ case EDIT: {
+ alert.setTitle(R.string.edit_keyserver_dialog_title);
+ mKeyserverEditText.setText(getArguments().getString(ARG_KEYSERVER));
+ break;
+ }
+ }
+
+ // we don't want dialog to be dismissed on click for keyserver addition or edit,
+ // 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
+ // actual listener set in onStart for adding keyservers or editing them
}
});
@@ -119,6 +158,23 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
}
});
+ switch (mDialogAction) {
+ case EDIT: {
+ alert.setNeutralButton(R.string.label_keyserver_dialog_delete,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ deleteKeyserver(mPosition);
+ }
+ });
+ break;
+ }
+ case ADD: {
+ // do nothing
+ break;
+ }
+ }
+
// 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/
@@ -155,25 +211,53 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- String keyserverUrl = mKeyserverEditText.getText().toString();
+ // behaviour same for edit and add
+ final String keyserverUrl = mKeyserverEditText.getText().toString();
if (mVerifyKeyserverCheckBox.isChecked()) {
- verifyConnection(keyserverUrl);
+ final Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(getActivity())
+ .getProxyPrefs();
+ Runnable ignoreTor = new Runnable() {
+ @Override
+ public void run() {
+ verifyConnection(keyserverUrl, null);
+ }
+ };
+
+ if (OrbotHelper.putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor, proxyPrefs,
+ getActivity())) {
+ verifyConnection(keyserverUrl, proxyPrefs.parcelableProxy.getProxy());
+ }
} else {
dismiss();
// return unverified keyserver back to activity
- addKeyserver(keyserverUrl, false);
+ keyserverEdited(keyserverUrl, false);
}
}
});
}
}
- public void addKeyserver(String keyserver, boolean verified) {
+ public void keyserverEdited(String keyserver, boolean verified) {
dismiss();
Bundle data = new Bundle();
+ data.putSerializable(MESSAGE_DIALOG_ACTION, mDialogAction);
data.putString(MESSAGE_KEYSERVER, keyserver);
data.putBoolean(MESSAGE_VERIFIED, verified);
+ if (mDialogAction == DialogAction.EDIT) {
+ data.putInt(MESSAGE_EDIT_POSITION, mPosition);
+ }
+
+ sendMessageToHandler(MESSAGE_OKAY, data);
+ }
+
+ public void deleteKeyserver(int position) {
+ dismiss();
+ Bundle data = new Bundle();
+ data.putSerializable(MESSAGE_DIALOG_ACTION, DialogAction.EDIT);
+ data.putInt(MESSAGE_EDIT_POSITION, position);
+ data.putBoolean(MESSAGE_KEYSERVER_DELETED, true);
+
sendMessageToHandler(MESSAGE_OKAY, data);
}
@@ -184,7 +268,7 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
sendMessageToHandler(MESSAGE_VERIFICATION_FAILED, data);
}
- public void verifyConnection(String keyserver) {
+ public void verifyConnection(String keyserver, final Proxy proxy) {
new AsyncTask<String, Void, FailureReason>() {
ProgressDialog mProgressDialog;
@@ -218,10 +302,11 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
}
URI newKeyserver = new URI(scheme, schemeSpecificPart, fragment);
- Log.d(Constants.TAG, "Converted URL" + newKeyserver);
+ Log.d("Converted URL", newKeyserver.toString());
- // just see if we can get a connection, then immediately close
- TlsHelper.openConnection(newKeyserver.toURL()).getInputStream().close();
+ OkHttpClient client = HkpKeyserver.getClient(newKeyserver.toURL(), proxy);
+ TlsHelper.pinCertificateIfNecessary(client, newKeyserver.toURL());
+ client.newCall(new Request.Builder().url(newKeyserver.toURL()).build()).execute();
} catch (TlsHelper.TlsHelperException e) {
reason = FailureReason.CONNECTION_FAILED;
} catch (MalformedURLException | URISyntaxException e) {
@@ -238,7 +323,7 @@ public class AddKeyserverDialogFragment extends DialogFragment implements OnEdit
protected void onPostExecute(FailureReason failureReason) {
mProgressDialog.dismiss();
if (failureReason == null) {
- addKeyserver(mKeyserver, true);
+ keyserverEdited(mKeyserver, true);
} else {
verificationFailed(failureReason);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEmailDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEmailDialogFragment.java
index 5b91b9d37..c55c75b55 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEmailDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEmailDialogFragment.java
@@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.Activity;
-import android.app.AlertDialog;
+import android.support.v7.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
index 0b1d39fc1..b51d081e1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
@@ -18,12 +18,12 @@
package org.sufficientlysecure.keychain.ui.dialog;
import android.annotation.TargetApi;
-import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
+import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
index fe4ba0262..bc82feb70 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
@@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.Activity;
-import android.app.AlertDialog;
+import android.support.v7.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java
index d2fa37cf7..d96879119 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java
@@ -27,7 +27,7 @@ import org.sufficientlysecure.keychain.R;
public class AdvancedAppSettingsDialogFragment extends DialogFragment {
private static final String ARG_PACKAGE_NAME = "package_name";
- private static final String ARG_SIGNATURE = "signature";
+ private static final String ARG_CERTIFICATE = "certificate";
/**
* Creates new instance of this fragment
@@ -36,7 +36,7 @@ public class AdvancedAppSettingsDialogFragment extends DialogFragment {
AdvancedAppSettingsDialogFragment frag = new AdvancedAppSettingsDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_PACKAGE_NAME, packageName);
- args.putString(ARG_SIGNATURE, digest);
+ args.putString(ARG_CERTIFICATE, digest);
frag.setArguments(args);
return frag;
@@ -62,10 +62,10 @@ public class AdvancedAppSettingsDialogFragment extends DialogFragment {
});
String packageName = getArguments().getString(ARG_PACKAGE_NAME);
- String signature = getArguments().getString(ARG_SIGNATURE);
+ String certificate = getArguments().getString(ARG_CERTIFICATE);
alert.setMessage(getString(R.string.api_settings_package_name) + ": " + packageName + "\n\n"
- + getString(R.string.api_settings_package_signature) + ": " + signature);
+ + getString(R.string.api_settings_package_certificate) + ": " + certificate);
return alert.show();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java
index 794af5b15..840b95a3c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java
@@ -17,42 +17,15 @@
package org.sufficientlysecure.keychain.ui.dialog;
-import android.app.AlertDialog;
import android.content.Context;
-import android.view.View;
-import android.widget.TextView;
-
-import org.sufficientlysecure.keychain.R;
+import android.support.v7.app.AlertDialog;
/**
- * This class extends AlertDiaog.Builder, styling the header using emphasis color.
- * Note that this class is a huge hack, because dialog boxes aren't easily stylable.
- * Also, the dialog NEEDS to be called with show() directly, not create(), otherwise
- * the order of internal operations will lead to a crash!
+ * Uses support lib's dialog builder. We can apply a theme here later!
*/
public class CustomAlertDialogBuilder extends AlertDialog.Builder {
public CustomAlertDialogBuilder(Context context) {
super(context);
}
-
- @Override
- public AlertDialog show() {
- AlertDialog dialog = super.show();
-
- int dividerId = dialog.getContext().getResources().getIdentifier("android:id/titleDivider", null, null);
- View divider = dialog.findViewById(dividerId);
- if (divider != null) {
- divider.setBackgroundColor(dialog.getContext().getResources().getColor(R.color.header_text));
- }
-
- int textViewId = dialog.getContext().getResources().getIdentifier("android:id/alertTitle", null, null);
- TextView tv = (TextView) dialog.findViewById(textViewId);
- if (tv != null) {
- tv.setTextColor(dialog.getContext().getResources().getColor(R.color.header_text));
- }
-
- return dialog;
- }
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
deleted file mode 100644
index 7fc9da9ec..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2013-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.Dialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.FragmentActivity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextView;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.operations.results.DeleteResult;
-import org.sufficientlysecure.keychain.operations.results.OperationResult;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.DeleteKeyringParcel;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.util.HashMap;
-
-public class DeleteKeyDialogFragment extends DialogFragment
- implements CryptoOperationHelper.Callback<DeleteKeyringParcel, DeleteResult> {
- private static final String ARG_MESSENGER = "messenger";
- private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids";
-
- public static final int MESSAGE_OKAY = 1;
- public static final int MESSAGE_ERROR = 0;
-
- private TextView mMainMessage;
- private View mInflateView;
-
- private Messenger mMessenger;
-
- // for CryptoOperationHelper.Callback
- private long[] mMasterKeyIds;
- private boolean mHasSecret;
- private CryptoOperationHelper<DeleteKeyringParcel, DeleteResult> mDeleteOpHelper;
-
- /**
- * Creates new instance of this delete file dialog fragment
- */
- public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] masterKeyIds) {
- DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment();
- Bundle args = new Bundle();
-
- args.putParcelable(ARG_MESSENGER, messenger);
- args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds);
-
- frag.setArguments(args);
-
- return frag;
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mDeleteOpHelper != null) {
- mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data);
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final FragmentActivity activity = getActivity();
- mMessenger = getArguments().getParcelable(ARG_MESSENGER);
-
- final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS);
-
- CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(activity);
-
- // Setup custom View to display in AlertDialog
- LayoutInflater inflater = activity.getLayoutInflater();
- mInflateView = inflater.inflate(R.layout.view_key_delete_fragment, null);
- builder.setView(mInflateView);
-
- mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage);
-
- final boolean hasSecret;
-
- // If only a single key has been selected
- if (masterKeyIds.length == 1) {
- long masterKeyId = masterKeyIds[0];
-
- try {
- HashMap<String, Object> data = new ProviderHelper(activity).getUnifiedData(
- masterKeyId, new String[]{
- KeyRings.USER_ID,
- KeyRings.HAS_ANY_SECRET
- }, new int[]{
- ProviderHelper.FIELD_TYPE_STRING,
- ProviderHelper.FIELD_TYPE_INTEGER
- }
- );
- String name;
- KeyRing.UserId mainUserId = KeyRing.splitUserId((String) data.get(KeyRings.USER_ID));
- if (mainUserId.name != null) {
- name = mainUserId.name;
- } else {
- name = getString(R.string.user_id_no_name);
- }
- hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1;
-
- if (hasSecret) {
- // show title only for secret key deletions,
- // see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior
- builder.setTitle(getString(R.string.title_delete_secret_key, name));
- mMainMessage.setText(getString(R.string.secret_key_deletion_confirmation, name));
- } else {
- mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name));
- }
- } catch (ProviderHelper.NotFoundException e) {
- dismiss();
- return null;
- }
- } else {
- mMainMessage.setText(R.string.key_deletion_confirmation_multi);
- hasSecret = false;
- }
-
- builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
-
- mMasterKeyIds = masterKeyIds;
- mHasSecret = hasSecret;
-
- mDeleteOpHelper = new CryptoOperationHelper<>
- (DeleteKeyDialogFragment.this, DeleteKeyDialogFragment.this,
- R.string.progress_deleting);
- mDeleteOpHelper.cryptoOperation();
- // do NOT dismiss here, it'll give
- // OperationHelper a null fragmentManager
- // dismiss();
- }
- });
- builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dismiss();
- }
- });
-
- return builder.show();
- }
-
- @Override
- public DeleteKeyringParcel createOperationInput() {
- return new DeleteKeyringParcel(mMasterKeyIds, mHasSecret);
- }
-
- @Override
- public void onCryptoOperationSuccess(DeleteResult result) {
- handleResult(result);
- }
-
- @Override
- public void onCryptoOperationCancelled() {
-
- }
-
- @Override
- public void onCryptoOperationError(DeleteResult result) {
- handleResult(result);
- }
-
- @Override
- public boolean onCryptoSetProgress(String msg, int progress, int max) {
- return false;
- }
-
- public void handleResult(DeleteResult result) {
- try {
- Bundle data = new Bundle();
- data.putParcelable(OperationResult.EXTRA_RESULT, result);
- Message msg = Message.obtain();
- msg.arg1 = ServiceProgressHandler.MessageStatus.OKAY.ordinal();
- msg.setData(data);
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "messenger error", e);
- }
- dismiss();
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyDialogFragment.java
index eafa129f0..b51648740 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyDialogFragment.java
@@ -35,7 +35,7 @@ public class EditSubkeyDialogFragment extends DialogFragment {
public static final int MESSAGE_CHANGE_EXPIRY = 1;
public static final int MESSAGE_REVOKE = 2;
public static final int MESSAGE_STRIP = 3;
- public static final int MESSAGE_KEYTOCARD = 4;
+ public static final int MESSAGE_MOVE_KEY_TO_CARD = 4;
private Messenger mMessenger;
@@ -78,7 +78,7 @@ public class EditSubkeyDialogFragment extends DialogFragment {
sendMessageToHandler(MESSAGE_STRIP, null);
break;
case 3:
- sendMessageToHandler(MESSAGE_KEYTOCARD, null);
+ sendMessageToHandler(MESSAGE_MOVE_KEY_TO_CARD, null);
break;
default:
break;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
index 37e05a61d..c9fb990a2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
@@ -24,6 +24,7 @@ import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
@@ -36,6 +37,8 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.Log;
import java.util.Calendar;
@@ -72,17 +75,19 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
/**
* Creates dialog
*/
+ @NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Activity activity = getActivity();
+ Activity activity = getActivity();
+
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
long creation = getArguments().getLong(ARG_CREATION);
long expiry = getArguments().getLong(ARG_EXPIRY);
- Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- creationCal.setTime(new Date(creation * 1000));
- final Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- expiryCal.setTime(new Date(expiry * 1000));
+ final Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ creationCal.setTimeInMillis(creation * 1000);
+ Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ expiryCal.setTimeInMillis(expiry * 1000);
// date picker works with default time zone, we need to convert from UTC to default timezone
creationCal.setTimeZone(TimeZone.getDefault());
@@ -123,11 +128,8 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
noExpiry.setChecked(false);
expiryLayout.setVisibility(View.VISIBLE);
- // convert from UTC to time zone of device
- Calendar expiryCalTimeZone = (Calendar) expiryCal.clone();
- expiryCalTimeZone.setTimeZone(TimeZone.getDefault());
currentExpiry.setText(DateFormat.getDateFormat(
- getActivity()).format(expiryCalTimeZone.getTime()));
+ getActivity()).format(expiryCal.getTime()));
}
// date picker works based on default time zone
@@ -175,10 +177,13 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
long numDays = (selectedCal.getTimeInMillis() / 86400000)
- - (expiryCal.getTimeInMillis() / 86400000);
+ - (creationCal.getTimeInMillis() / 86400000);
if (numDays <= 0) {
- Log.e(Constants.TAG, "Should not happen! Expiry num of days <= 0!");
- throw new RuntimeException();
+ Activity activity = getActivity();
+ if (activity != null) {
+ Notify.create(activity, R.string.error_expiry_past, Style.ERROR).show();
+ }
+ return;
}
expiry = selectedCal.getTime().getTime() / 1000;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
index 63b6d26ac..5ef8618ce 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
@@ -136,6 +136,7 @@ public class FileDialogFragment extends DialogFragment {
mCheckBox.setEnabled(true);
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setText(checkboxText);
+ mCheckBox.setChecked(true);
}
alert.setView(view);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/OrbotStartDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/OrbotStartDialogFragment.java
new file mode 100644
index 000000000..d1d22b6d7
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/OrbotStartDialogFragment.java
@@ -0,0 +1,126 @@
+/*
+ * 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.support.v7.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.support.v4.app.DialogFragment;
+import android.view.ContextThemeWrapper;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
+
+/**
+ * displays a dialog asking the user to enable Tor
+ */
+public class OrbotStartDialogFragment extends DialogFragment {
+ private static final String ARG_MESSENGER = "messenger";
+ private static final String ARG_TITLE = "title";
+ private static final String ARG_MESSAGE = "message";
+ private static final String ARG_MIDDLE_BUTTON = "middleButton";
+
+ public static final int MESSAGE_MIDDLE_BUTTON = 1;
+ public static final int MESSAGE_DIALOG_DISMISSED = 2; // for either cancel or enable pressed
+
+ public static OrbotStartDialogFragment newInstance(Messenger messenger, int title, int message, int middleButton) {
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_MESSENGER, messenger);
+ args.putInt(ARG_TITLE, title);
+ args.putInt(ARG_MESSAGE, message);
+ args.putInt(ARG_MIDDLE_BUTTON, middleButton);
+
+ OrbotStartDialogFragment fragment = new OrbotStartDialogFragment();
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+ final Messenger messenger = getArguments().getParcelable(ARG_MESSENGER);
+ int title = getArguments().getInt(ARG_TITLE);
+ final int message = getArguments().getInt(ARG_MESSAGE);
+ int middleButton = getArguments().getInt(ARG_MIDDLE_BUTTON);
+ final Activity activity = getActivity();
+
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
+
+ CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme);
+ builder.setTitle(title).setMessage(message);
+
+ builder.setNegativeButton(R.string.orbot_start_dialog_cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Message msg = Message.obtain();
+ msg.what = MESSAGE_DIALOG_DISMISSED;
+ try {
+ messenger.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);
+ }
+
+ }
+ });
+
+ builder.setPositiveButton(R.string.orbot_start_dialog_start, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ getActivity().startActivityForResult(OrbotHelper.getOrbotStartIntent(), 1);
+
+ Message msg = Message.obtain();
+ msg.what = MESSAGE_DIALOG_DISMISSED;
+ try {
+ messenger.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);
+ }
+ }
+ });
+
+ builder.setNeutralButton(middleButton, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Message msg = new Message();
+ msg.what = MESSAGE_MIDDLE_BUTTON;
+ try {
+ messenger.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);
+ }
+ }
+ });
+
+ return builder.show();
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PreferenceInstallDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PreferenceInstallDialogFragment.java
new file mode 100644
index 000000000..3f8bce28b
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PreferenceInstallDialogFragment.java
@@ -0,0 +1,75 @@
+/*
+ * 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.Dialog;
+import android.os.Bundle;
+import android.os.Messenger;
+import android.app.DialogFragment;
+
+import org.sufficientlysecure.keychain.ui.util.InstallDialogFragmentHelper;
+
+public class PreferenceInstallDialogFragment extends DialogFragment {
+
+ public static final int MESSAGE_MIDDLE_CLICKED = 1;
+ public static final int MESSAGE_DIALOG_DISMISSED = 2;
+
+ /**
+ * Creates a dialog which prompts the user to install an application. Consists of two default buttons ("Install"
+ * and "Cancel") and an optional third button. Callbacks are provided only for the middle button, if set.
+ *
+ * @param messenger required only for callback from middle button if it has been set
+ * @param title
+ * @param message content of dialog
+ * @param packageToInstall package name of application to install
+ * @param middleButton if not null, adds a third button to the app with a call back
+ * @return The dialog to display
+ */
+ public static PreferenceInstallDialogFragment newInstance(Messenger messenger, int title, int message,
+ String packageToInstall, int middleButton, boolean
+ useMiddleButton) {
+ PreferenceInstallDialogFragment frag = new PreferenceInstallDialogFragment();
+ Bundle args = new Bundle();
+
+ InstallDialogFragmentHelper.wrapIntoArgs(messenger, title, message, packageToInstall, middleButton,
+ useMiddleButton, args);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ /**
+ * To create a DialogFragment with only two buttons
+ *
+ * @param title
+ * @param message
+ * @param packageToInstall
+ * @return
+ */
+ public static PreferenceInstallDialogFragment newInstance(int title, int message,
+ String packageToInstall) {
+ return newInstance(null, title, message, packageToInstall, -1, false);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return InstallDialogFragmentHelper.getInstallDialogFromArgs(getArguments(), getActivity(),
+ MESSAGE_MIDDLE_CLICKED, MESSAGE_DIALOG_DISMISSED);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
index 52a90b323..764291dd0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
@@ -35,6 +35,7 @@ import android.widget.Button;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.KeychainService;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
/**
* meant to be used
@@ -98,10 +99,7 @@ public class ProgressDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
- // if the progress dialog is displayed from the application class, design is missing
- // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
- ContextThemeWrapper context = new ContextThemeWrapper(activity,
- R.style.Theme_AppCompat_Light);
+ ContextThemeWrapper context = ThemeChanger.getDialogThemeWrapper(activity);
ProgressDialog dialog = new ProgressDialog(context);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
index 4eb253825..a990682f6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
@@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.Activity;
-import android.app.AlertDialog;
+import android.support.v7.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SupportInstallDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SupportInstallDialogFragment.java
new file mode 100644
index 000000000..b2b71b364
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SupportInstallDialogFragment.java
@@ -0,0 +1,76 @@
+/*
+ * 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.Dialog;
+import android.os.Bundle;
+import android.os.Messenger;
+import android.support.v4.app.DialogFragment;
+
+import org.sufficientlysecure.keychain.ui.util.InstallDialogFragmentHelper;
+
+public class SupportInstallDialogFragment extends DialogFragment {
+
+ public static final int MESSAGE_MIDDLE_CLICKED = 1;
+ public static final int MESSAGE_DIALOG_DISMISSED = 2;
+
+ /**
+ * Creates a dialog which prompts the user to install an application. Consists of two default buttons ("Install"
+ * and "Cancel") and an optional third button. Callbacks are provided only for the middle button, if set.
+ *
+ * @param messenger required only for callback from middle button if it has been set
+ * @param title
+ * @param message content of dialog
+ * @param packageToInstall package name of application to install
+ * @param middleButton if not null, adds a third button to the app with a call back
+ * @return The dialog to display
+ */
+ public static SupportInstallDialogFragment newInstance(Messenger messenger, int title, int message,
+ String packageToInstall, int middleButton, boolean
+ useMiddleButton) {
+ SupportInstallDialogFragment frag = new SupportInstallDialogFragment();
+ Bundle args = new Bundle();
+
+ InstallDialogFragmentHelper.wrapIntoArgs(messenger, title, message, packageToInstall, middleButton,
+ useMiddleButton, args);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ /**
+ * To create a DialogFragment with only two buttons
+ *
+ * @param title
+ * @param message
+ * @param packageToInstall
+ * @return
+ */
+ public static SupportInstallDialogFragment newInstance(int title, int message,
+ String packageToInstall) {
+ return newInstance(null, title, message, packageToInstall, -1, false);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+ return InstallDialogFragmentHelper.getInstallDialogFromArgs(getArguments(), getActivity(),
+ MESSAGE_MIDDLE_CLICKED, MESSAGE_DIALOG_DISMISSED);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java
index eb5c3df45..902a7ec56 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java
@@ -18,9 +18,11 @@
package org.sufficientlysecure.keychain.ui.util;
import android.content.Context;
+import android.content.res.Resources.Theme;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.StrikethroughSpan;
+import android.util.TypedValue;
public class FormattingUtils {
@@ -32,4 +34,10 @@ public class FormattingUtils {
return (int) ((px / context.getResources().getDisplayMetrics().density) + 0.5f);
}
+ public static int getColorFromAttr(Context context, int attr) {
+ TypedValue typedValue = new TypedValue();
+ Theme theme = context.getTheme();
+ theme.resolveAttribute(attr, typedValue, true);
+ return typedValue.data;
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Highlighter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Highlighter.java
index 69338aa3e..ac34d5526 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Highlighter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Highlighter.java
@@ -22,6 +22,7 @@ import android.text.Spannable;
import android.text.style.ForegroundColorSpan;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -44,9 +45,12 @@ public class Highlighter {
Pattern pattern = Pattern.compile("(?i)(" + mQuery.trim().replaceAll("\\s+", "|") + ")");
Matcher matcher = pattern.matcher(text);
+
+ int colorEmphasis = FormattingUtils.getColorFromAttr(mContext, R.attr.colorEmphasis);
+
while (matcher.find()) {
highlight.setSpan(
- new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)),
+ new ForegroundColorSpan(colorEmphasis),
matcher.start(),
matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/InstallDialogFragmentHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/InstallDialogFragmentHelper.java
new file mode 100644
index 000000000..b2213ed10
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/InstallDialogFragmentHelper.java
@@ -0,0 +1,132 @@
+/*
+ * 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.util;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.support.v7.app.AlertDialog;
+import android.view.ContextThemeWrapper;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
+import org.sufficientlysecure.keychain.util.Log;
+
+public class InstallDialogFragmentHelper {
+ private static final String ARG_MESSENGER = "messenger";
+ private static final String ARG_TITLE = "title";
+ private static final String ARG_MESSAGE = "message";
+ private static final String ARG_MIDDLE_BUTTON = "middleButton";
+ private static final String ARG_INSTALL_PATH = "installPath";
+ private static final String ARG_USE_MIDDLE_BUTTON = "useMiddleButton";
+
+ private static final String PLAY_STORE_PATH = "market://search?q=pname:";
+
+ public static void wrapIntoArgs(Messenger messenger, int title, int message, String packageToInstall,
+ int middleButton, boolean useMiddleButton, Bundle args) {
+ args.putParcelable(ARG_MESSENGER, messenger);
+
+ args.putInt(ARG_TITLE, title);
+ args.putInt(ARG_MESSAGE, message);
+ args.putInt(ARG_MIDDLE_BUTTON, middleButton);
+ args.putString(ARG_INSTALL_PATH, PLAY_STORE_PATH + packageToInstall);
+ args.putBoolean(ARG_USE_MIDDLE_BUTTON, useMiddleButton);
+ }
+
+ public static AlertDialog getInstallDialogFromArgs(Bundle args, final Activity activity,
+ final int messengerMiddleButtonClicked,
+ final int messengerDialogDimissed) {
+ final Messenger messenger = args.getParcelable(ARG_MESSENGER);
+
+ final int title = args.getInt(ARG_TITLE);
+ final int message = args.getInt(ARG_MESSAGE);
+ final int middleButton = args.getInt(ARG_MIDDLE_BUTTON);
+ final String installPath = args.getString(ARG_INSTALL_PATH);
+ final boolean useMiddleButton = args.getBoolean(ARG_USE_MIDDLE_BUTTON);
+
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
+ CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme);
+
+ builder.setTitle(title).setMessage(message);
+
+ builder.setNegativeButton(R.string.orbot_install_dialog_cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Message msg = Message.obtain();
+ msg.what = messengerDialogDimissed;
+ try {
+ messenger.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);
+ }
+ }
+ });
+
+ builder.setPositiveButton(R.string.orbot_install_dialog_install,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Uri uri = Uri.parse(installPath);
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ activity.startActivity(intent);
+
+ Message msg = Message.obtain();
+ msg.what = messengerDialogDimissed;
+ try {
+ messenger.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);
+ }
+ }
+ }
+ );
+
+ if (useMiddleButton) {
+ builder.setNeutralButton(middleButton,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Message msg = Message.obtain();
+ msg.what = messengerMiddleButtonClicked;
+ try {
+ messenger.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);
+ }
+ }
+ }
+ );
+ }
+
+ return builder.show();
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java
index a3cd63d13..224e0085b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java
@@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
+import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
import java.nio.ByteBuffer;
@@ -449,11 +450,11 @@ public class KeyFormattingUtils {
if (signatureResult != null && signatureResult.isSignatureOnly()) {
encIcon = R.drawable.status_lock_open_24dp;
encText = R.string.decrypt_result_not_encrypted;
- encColor = R.color.android_red_light;
+ encColor = R.color.key_flag_red;
} else {
encIcon = R.drawable.status_lock_closed_24dp;
encText = R.string.decrypt_result_encrypted;
- encColor = R.color.android_green_light;
+ encColor = R.color.key_flag_green;
}
int encColorRes = context.getResources().getColor(encColor);
@@ -470,7 +471,7 @@ public class KeyFormattingUtils {
sigText = R.string.decrypt_result_no_signature;
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
- sigColor = R.color.bg_gray;
+ sigColor = R.color.key_flag_gray;
// won't be used, but makes compiler happy
sigActionText = 0;
@@ -481,7 +482,7 @@ public class KeyFormattingUtils {
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
sigText = R.string.decrypt_result_signature_certified;
sigIcon = R.drawable.status_signature_verified_cutout_24dp;
- sigColor = R.color.android_green_light;
+ sigColor = R.color.key_flag_green;
sigActionText = R.string.decrypt_result_action_show;
sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
@@ -491,7 +492,7 @@ public class KeyFormattingUtils {
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
sigText = R.string.decrypt_result_signature_uncertified;
sigIcon = R.drawable.status_signature_unverified_cutout_24dp;
- sigColor = R.color.android_orange_light;
+ sigColor = R.color.key_flag_orange;
sigActionText = R.string.decrypt_result_action_show;
sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
@@ -501,7 +502,7 @@ public class KeyFormattingUtils {
case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: {
sigText = R.string.decrypt_result_signature_revoked_key;
sigIcon = R.drawable.status_signature_revoked_cutout_24dp;
- sigColor = R.color.android_red_light;
+ sigColor = R.color.key_flag_red;
sigActionText = R.string.decrypt_result_action_show;
sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
@@ -511,7 +512,7 @@ public class KeyFormattingUtils {
case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: {
sigText = R.string.decrypt_result_signature_expired_key;
sigIcon = R.drawable.status_signature_expired_cutout_24dp;
- sigColor = R.color.android_red_light;
+ sigColor = R.color.key_flag_red;
sigActionText = R.string.decrypt_result_action_show;
sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
@@ -521,7 +522,7 @@ public class KeyFormattingUtils {
case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: {
sigText = R.string.decrypt_result_signature_missing_key;
sigIcon = R.drawable.status_signature_unknown_cutout_24dp;
- sigColor = R.color.android_red_light;
+ sigColor = R.color.key_flag_red;
sigActionText = R.string.decrypt_result_action_Lookup;
sigActionIcon = R.drawable.ic_file_download_grey_24dp;
@@ -532,7 +533,7 @@ public class KeyFormattingUtils {
case OpenPgpSignatureResult.SIGNATURE_ERROR: {
sigText = R.string.decrypt_result_invalid_signature;
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
- sigColor = R.color.android_red_light;
+ sigColor = R.color.key_flag_red;
sigActionText = R.string.decrypt_result_action_show;
sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
@@ -595,7 +596,7 @@ public class KeyFormattingUtils {
context.getResources().getDrawable(R.drawable.status_signature_verified_cutout_24dp));
}
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_green_light;
+ color = R.color.key_flag_green;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -608,7 +609,7 @@ public class KeyFormattingUtils {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_lock_closed_24dp));
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_green_light;
+ color = R.color.key_flag_green;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -627,7 +628,7 @@ public class KeyFormattingUtils {
context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout_24dp));
}
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_orange_light;
+ color = R.color.key_flag_orange;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -640,7 +641,7 @@ public class KeyFormattingUtils {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24dp));
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_red_light;
+ color = R.color.key_flag_red;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -659,7 +660,7 @@ public class KeyFormattingUtils {
context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout_24dp));
}
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_red_light;
+ color = R.color.key_flag_red;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -677,7 +678,7 @@ public class KeyFormattingUtils {
context.getResources().getDrawable(R.drawable.status_signature_expired_cutout_24dp));
}
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_red_light;
+ color = R.color.key_flag_red;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -690,7 +691,7 @@ public class KeyFormattingUtils {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_lock_open_24dp));
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_red_light;
+ color = R.color.key_flag_red;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -703,7 +704,7 @@ public class KeyFormattingUtils {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24dp));
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_red_light;
+ color = R.color.key_flag_red;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -716,7 +717,7 @@ public class KeyFormattingUtils {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24dp));
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.android_red_light;
+ color = R.color.key_flag_red;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
@@ -730,7 +731,7 @@ public class KeyFormattingUtils {
statusIcon.setImageDrawable(
context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24dp));
if (color == KeyFormattingUtils.DEFAULT_COLOR) {
- color = R.color.bg_gray;
+ color = R.color.key_flag_gray;
}
statusIcon.setColorFilter(context.getResources().getColor(color),
PorterDuff.Mode.SRC_IN);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ThemeChanger.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ThemeChanger.java
new file mode 100644
index 000000000..f53e43528
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ThemeChanger.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 Thialfihar <thi@thialfihar.org>
+ *
+ * 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.util;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Preferences;
+
+public class ThemeChanger {
+ private Context mContext;
+ private Preferences mPreferences;
+ private String mCurrentTheme = null;
+
+ static public ContextThemeWrapper getDialogThemeWrapper(Context context) {
+ Preferences preferences = Preferences.getPreferences(context);
+
+ // if the dialog is displayed from the application class, design is missing.
+ // hack to get holo design (which is not automatically applied due to activity's
+ // Theme.NoDisplay)
+ if (Constants.Pref.Theme.DARK.equals(preferences.getTheme())) {
+ return new ContextThemeWrapper(context, R.style.Theme_AppCompat_Dialog);
+ } else {
+ return new ContextThemeWrapper(context, R.style.Theme_AppCompat_Light_Dialog);
+ }
+ }
+
+ public ThemeChanger(Context context) {
+ mContext = context;
+ mPreferences = Preferences.getPreferences(mContext);
+ }
+
+ /**
+ * Apply the theme set in preferences if it isn't equal to mCurrentTheme
+ * anymore or mCurrentTheme hasn't been set yet.
+ * If a new theme is applied in this method, then return true, so
+ * the caller can re-create the activity, if need be.
+ */
+ public boolean changeTheme() {
+ String newTheme = mPreferences.getTheme();
+ if (mCurrentTheme != null && mCurrentTheme.equals(newTheme)) {
+ return false;
+ }
+
+ int themeId = R.style.LightTheme;
+ if (Constants.Pref.Theme.DARK.equals(newTheme)) {
+ themeId = R.style.DarkTheme;
+ }
+
+ ContextThemeWrapper w = new ContextThemeWrapper(mContext, themeId);
+ mContext.getTheme().setTo(w.getTheme());
+ mCurrentTheme = newTheme;
+
+ return true;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java
new file mode 100644
index 000000000..95199bcd5
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.sufficientlysecure.keychain.ui.util.recyclerview;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+public class DividerItemDecoration extends RecyclerView.ItemDecoration {
+
+ private static final int[] ATTRS = new int[]{
+ android.R.attr.listDivider
+ };
+
+ public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
+
+ public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
+
+ private Drawable mDivider;
+
+ private int mOrientation;
+
+ public DividerItemDecoration(Context context, int orientation) {
+ final TypedArray a = context.obtainStyledAttributes(ATTRS);
+ mDivider = a.getDrawable(0);
+ a.recycle();
+ setOrientation(orientation);
+ }
+
+ public void setOrientation(int orientation) {
+ if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
+ throw new IllegalArgumentException("invalid orientation");
+ }
+ mOrientation = orientation;
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (mOrientation == VERTICAL_LIST) {
+ drawVertical(c, parent);
+ } else {
+ drawHorizontal(c, parent);
+ }
+ }
+
+ public void drawVertical(Canvas c, RecyclerView parent) {
+ final int left = parent.getPaddingLeft();
+ final int right = parent.getWidth() - parent.getPaddingRight();
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = parent.getChildAt(i);
+ final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
+ .getLayoutParams();
+ final int top = child.getBottom() + params.bottomMargin;
+ final int bottom = top + mDivider.getIntrinsicHeight();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(c);
+ }
+ }
+
+ public void drawHorizontal(Canvas c, RecyclerView parent) {
+ final int top = parent.getPaddingTop();
+ final int bottom = parent.getHeight() - parent.getPaddingBottom();
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = parent.getChildAt(i);
+ final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
+ .getLayoutParams();
+ final int left = child.getRight() + params.rightMargin;
+ final int right = left + mDivider.getIntrinsicHeight();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(c);
+ }
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+ RecyclerView.State state) {
+ if (mOrientation == VERTICAL_LIST) {
+ outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
+ } else {
+ outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperAdapter.java
new file mode 100644
index 000000000..c691182bf
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperAdapter.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Paul Burke
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.sufficientlysecure.keychain.ui.util.recyclerview;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+/**
+ * Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
+ */
+public interface ItemTouchHelperAdapter {
+
+ /**
+ * Called when an item has been dragged far enough to trigger a move. This is called every time
+ * an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/>
+ * <br/>
+ * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
+ * adjusting the underlying data to reflect this move.
+ *
+ * @param fromPosition The start position of the moved item.
+ * @param toPosition Then resolved position of the moved item.
+ * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
+ * @see RecyclerView.ViewHolder#getAdapterPosition()
+ */
+ void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target,
+ int fromPosition, int toPosition);
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperDragCallback.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperDragCallback.java
new file mode 100644
index 000000000..0fd24581d
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperDragCallback.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 Paul Burke
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.sufficientlysecure.keychain.ui.util.recyclerview;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+/**
+ * An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and
+ * swipe-to-dismiss. Drag events are automatically started by an item long-press.<br/>
+ * </br/>
+ * Expects the <code>RecyclerView.Adapter</code> to listen for {@link
+ * ItemTouchHelperAdapter} callbacks and the <code>RecyclerView.ViewHolder</code> to implement
+ * {@link ItemTouchHelperViewHolder}.
+ */
+public class ItemTouchHelperDragCallback extends ItemTouchHelper.Callback {
+
+ private final ItemTouchHelperAdapter mAdapter;
+
+ public ItemTouchHelperDragCallback(ItemTouchHelperAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ @Override
+ public boolean isLongPressDragEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isItemViewSwipeEnabled() {
+ return false;
+ }
+
+ @Override
+ public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ // Enable drag and swipe in both directions
+ final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+ final int swipeFlags = 0;
+ return makeMovementFlags(dragFlags, swipeFlags);
+ }
+
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source,
+ RecyclerView.ViewHolder target) {
+ if (source.getItemViewType() != target.getItemViewType()) {
+ return false;
+ }
+
+ // Notify the adapter of the move
+ mAdapter.onItemMove(source, target, source.getAdapterPosition(), target.getAdapterPosition());
+ return true;
+ }
+
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
+ // we don't support swipe
+ }
+
+ @Override
+ public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+ if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
+ // Let the view holder know that this item is being moved or dragged
+ ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
+ itemViewHolder.onItemSelected();
+ }
+
+ super.onSelectedChanged(viewHolder, actionState);
+ }
+
+ @Override
+ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ super.clearView(recyclerView, viewHolder);
+
+ // Tell the view holder it's time to restore the idle state
+ ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
+ itemViewHolder.onItemClear();
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperViewHolder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperViewHolder.java
new file mode 100644
index 000000000..97e70d71e
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/ItemTouchHelperViewHolder.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Paul Burke
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.sufficientlysecure.keychain.ui.util.recyclerview;
+
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+/**
+ * Interface to notify an item ViewHolder of relevant callbacks from {@link
+ * android.support.v7.widget.helper.ItemTouchHelper.Callback}.
+ */
+public interface ItemTouchHelperViewHolder {
+
+ /**
+ * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
+ * Implementations should update the item view to indicate it's active state.
+ */
+ void onItemSelected();
+
+
+ /**
+ * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
+ * state should be cleared.
+ */
+ void onItemClear();
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/RecyclerItemClickListener.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/RecyclerItemClickListener.java
new file mode 100644
index 000000000..7efcbb30c
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/RecyclerItemClickListener.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Jacob Tabak
+ *
+ * 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.util.recyclerview;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * based on http://stackoverflow.com/a/26196831/3000919
+ */
+public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
+ private OnItemClickListener mListener;
+ private boolean mIgnoreTouch = false;
+
+ public interface OnItemClickListener {
+ void onItemClick(View view, int position);
+ }
+
+ GestureDetector mGestureDetector;
+
+ public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
+ mListener = listener;
+ mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
+ if (mIgnoreTouch) {
+ return false;
+ }
+ View childView = view.findChildViewUnder(e.getX(), e.getY());
+ if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
+ mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
+ // TODO: should we move mListener.onItemClick here
+ }
+
+ @Override
+ public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ mIgnoreTouch = disallowIntercept;
+ }
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
index 0fed46544..6cd33aada 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
@@ -109,14 +109,18 @@ public class CertifyKeySpinner extends KeySpinner {
@Override
boolean isItemEnabled(Cursor cursor) {
+ // "none" entry is always enabled!
+ if (cursor.getPosition() == 0) {
+ return true;
+ }
+
if (cursor.getInt(KeyAdapter.INDEX_IS_REVOKED) != 0) {
return false;
}
if (cursor.getInt(KeyAdapter.INDEX_IS_EXPIRED) != 0) {
return false;
}
- // don't invalidate the "None" entry, which is also null!
- if (cursor.getPosition() != 0 && cursor.isNull(mIndexHasCertify)) {
+ if (cursor.isNull(mIndexHasCertify)) {
return false;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java
deleted file mode 100644
index ec91b9fe4..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
- *
- * 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.widget;
-
-public interface Editor {
- public interface EditorListener {
- public void onDeleted(Editor editor, boolean wasNewItem);
- public void onEdited();
- }
-
- public void setEditorListener(EditorListener listener);
- public boolean needsSaving();
-}
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 e55f6b1ad..494ccb6d3 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
@@ -75,10 +75,10 @@ public class EmailEditText extends AppCompatAutoCompleteTextView {
Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
if (emailMatcher.matches()) {
EmailEditText.this.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_ok, 0);
+ R.drawable.ic_stat_retyped_ok, 0);
} else {
EmailEditText.this.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_bad, 0);
+ R.drawable.ic_stat_retyped_bad, 0);
}
} else {
// remove drawable if email is empty
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java
deleted file mode 100644
index 3fd01958a..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
- *
- * 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.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import org.sufficientlysecure.keychain.R;
-
-public class KeyServerEditor extends LinearLayout implements Editor, OnClickListener {
- private EditorListener mEditorListener = null;
-
- ImageButton mDeleteButton;
- TextView mServer;
-
- public KeyServerEditor(Context context) {
- super(context);
- }
-
- public KeyServerEditor(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- setDrawingCacheEnabled(true);
- setAlwaysDrawnWithCacheEnabled(true);
-
- mServer = (TextView) findViewById(R.id.server);
-
- mDeleteButton = (ImageButton) findViewById(R.id.delete);
- mDeleteButton.setOnClickListener(this);
-
- super.onFinishInflate();
- }
-
- public void setValue(String value) {
- mServer.setText(value);
- }
-
- public String getValue() {
- return mServer.getText().toString().trim();
- }
-
- public void onClick(View v) {
- final ViewGroup parent = (ViewGroup) getParent();
- if (v == mDeleteButton) {
- parent.removeView(this);
- if (mEditorListener != null) {
- mEditorListener.onDeleted(this, false);
- }
- }
- }
-
- @Override
- public boolean needsSaving() {
- return false;
- }
-
- public void setEditorListener(EditorListener listener) {
- mEditorListener = listener;
- }
-}
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 5050c01af..1884daf12 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
@@ -84,7 +84,8 @@ public abstract class KeySpinner extends AppCompatSpinner implements
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mListener != null) {
- mListener.onKeyChanged(id);
+ long keyId = getSelectedKeyId(getItemAtPosition(position));
+ mListener.onKeyChanged(keyId);
}
}
@@ -137,6 +138,10 @@ public abstract class KeySpinner extends AppCompatSpinner implements
public long getSelectedKeyId() {
Object item = getSelectedItem();
+ return getSelectedKeyId(item);
+ }
+
+ public long getSelectedKeyId(Object item) {
if (item instanceof KeyItem) {
return ((KeyItem) item).mKeyId;
}
@@ -186,7 +191,7 @@ public abstract class KeySpinner extends AppCompatSpinner implements
}
@Override
- public Object getItem(int position) {
+ public KeyItem getItem(int position) {
if (position == 0) {
return null;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java
index 0ec145657..a7ead8039 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/PasswordStrengthView.java
@@ -31,7 +31,9 @@ import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
/**
* Created by Matt Allen
@@ -97,9 +99,9 @@ public class PasswordStrengthView extends View {
public PasswordStrengthView(Context context, AttributeSet attrs) {
super(context, attrs);
- int COLOR_FAIL = getResources().getColor(R.color.android_red_light);
- int COLOR_WEAK = getResources().getColor(R.color.android_orange_light);
- int COLOR_STRONG = getResources().getColor(R.color.android_green_light);
+ int COLOR_FAIL = getResources().getColor(R.color.password_strength_low);
+ int COLOR_WEAK = getResources().getColor(R.color.password_strength_medium);
+ int COLOR_STRONG = getResources().getColor(R.color.password_strength_high);
TypedArray style = context.getTheme().obtainStyledAttributes(
attrs,
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
index c59ad7a12..8fb9e38aa 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
@@ -72,13 +72,18 @@ public class SignKeySpinner extends KeySpinner {
@Override
boolean isItemEnabled(Cursor cursor) {
+ // "none" entry is always enabled!
+ if (cursor.getPosition() == 0) {
+ return true;
+ }
+
if (cursor.getInt(KeyAdapter.INDEX_IS_REVOKED) != 0) {
return false;
}
if (cursor.getInt(KeyAdapter.INDEX_IS_EXPIRED) != 0) {
return false;
}
- if (cursor.getInt(mIndexHasSign) == 0) {
+ if (cursor.isNull(mIndexHasSign)) {
return false;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
index b814f72b2..d7491ab26 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
@@ -27,6 +27,7 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -34,6 +35,7 @@ import java.util.Locale;
import java.util.Set;
public class EmailKeyHelper {
+ // TODO: Make this not require a proxy in it's constructor, redesign when it is to be used
// to import keys, simply use CryptoOperationHelper with this callback
public abstract class ImportContactKeysCallback
implements CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
@@ -41,14 +43,15 @@ public class EmailKeyHelper {
private ArrayList<ParcelableKeyRing> mKeyList;
private String mKeyserver;
- public ImportContactKeysCallback(Context context, String keyserver) {
- this(context, ContactHelper.getContactMails(context), keyserver);
+ public ImportContactKeysCallback(Context context, String keyserver, Proxy proxy) {
+ this(context, ContactHelper.getContactMails(context), keyserver, proxy);
}
- public ImportContactKeysCallback(Context context, List<String> mails, String keyserver) {
+ public ImportContactKeysCallback(Context context, List<String> mails, String keyserver,
+ Proxy proxy) {
Set<ImportKeysListEntry> entries = new HashSet<>();
for (String mail : mails) {
- entries.addAll(getEmailKeys(context, mail));
+ entries.addAll(getEmailKeys(context, mail, proxy));
}
// Put them in a list and import
@@ -65,7 +68,7 @@ public class EmailKeyHelper {
}
}
- public static Set<ImportKeysListEntry> getEmailKeys(Context context, String mail) {
+ public static Set<ImportKeysListEntry> getEmailKeys(Context context, String mail, Proxy proxy) {
Set<ImportKeysListEntry> keys = new HashSet<>();
// Try _hkp._tcp SRV record first
@@ -73,7 +76,7 @@ public class EmailKeyHelper {
if (mailparts.length == 2) {
HkpKeyserver hkp = HkpKeyserver.resolve(mailparts[1]);
if (hkp != null) {
- keys.addAll(getEmailKeys(mail, hkp));
+ keys.addAll(getEmailKeys(mail, hkp, proxy));
}
}
@@ -82,16 +85,17 @@ public class EmailKeyHelper {
String server = Preferences.getPreferences(context).getPreferredKeyserver();
if (server != null) {
HkpKeyserver hkp = new HkpKeyserver(server);
- keys.addAll(getEmailKeys(mail, hkp));
+ keys.addAll(getEmailKeys(mail, hkp, proxy));
}
}
return keys;
}
- public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer) {
+ public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer,
+ Proxy proxy) {
Set<ImportKeysListEntry> keys = new HashSet<>();
try {
- for (ImportKeysListEntry key : keyServer.search(mail)) {
+ for (ImportKeysListEntry key : keyServer.search(mail, proxy)) {
if (key.isRevoked() || key.isExpired()) continue;
for (String userId : key.getUserIds()) {
if (userId.toLowerCase().contains(mail.toLowerCase(Locale.ENGLISH))) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
index 9567fc9c0..5f2329170 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
@@ -17,6 +17,9 @@
package org.sufficientlysecure.keychain.util;
+
+import java.io.File;
+
import android.support.v4.app.FragmentActivity;
import org.sufficientlysecure.keychain.Constants;
@@ -25,15 +28,12 @@ import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
-import java.io.File;
-
public class ExportHelper
implements CryptoOperationHelper.Callback <ExportKeyringParcel, ExportResult> {
protected File mExportFile;
FragmentActivity mActivity;
- private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mExportOpHelper;
private boolean mExportSecret;
private long[] mMasterKeyIds;
@@ -42,15 +42,13 @@ public class ExportHelper
this.mActivity = activity;
}
- /**
- * Show dialog where to export keys
- */
- public void showExportKeysDialog(final long[] masterKeyIds, final File exportFile,
- final boolean showSecretCheckbox) {
+ /** Show dialog where to export keys */
+ public void showExportKeysDialog(final Long masterKeyId, final File exportFile,
+ final boolean exportSecret) {
mExportFile = exportFile;
- String title = null;
- if (masterKeyIds == null) {
+ String title;
+ if (masterKeyId == null) {
// export all keys
title = mActivity.getString(R.string.title_export_keys);
} else {
@@ -58,17 +56,24 @@ public class ExportHelper
title = mActivity.getString(R.string.title_export_key);
}
- String message = mActivity.getString(R.string.specify_file_to_export_to);
- String checkMsg = showSecretCheckbox ?
- mActivity.getString(R.string.also_export_secret_keys) : null;
+ String message;
+ if (exportSecret) {
+ message = mActivity.getString(masterKeyId == null
+ ? R.string.specify_backup_dest_secret
+ : R.string.specify_backup_dest_secret_single);
+ } else {
+ message = mActivity.getString(masterKeyId == null
+ ? R.string.specify_backup_dest
+ : R.string.specify_backup_dest_single);
+ }
FileHelper.saveFile(new FileHelper.FileDialogCallback() {
@Override
public void onFileSelected(File file, boolean checked) {
mExportFile = file;
- exportKeys(masterKeyIds, checked);
+ exportKeys(masterKeyId == null ? null : new long[] { masterKeyId }, exportSecret);
}
- }, mActivity.getSupportFragmentManager() ,title, message, exportFile, checkMsg);
+ }, mActivity.getSupportFragmentManager(), title, message, exportFile, null);
}
// TODO: If ExportHelper requires pending data (see CryptoOPerationHelper), activities using
@@ -82,8 +87,9 @@ public class ExportHelper
mExportSecret = exportSecret;
mMasterKeyIds = masterKeyIds; // if masterKeyIds is null it means export all
- mExportOpHelper = new CryptoOperationHelper(mActivity, this, R.string.progress_exporting);
- mExportOpHelper.cryptoOperation();
+ CryptoOperationHelper<ExportKeyringParcel, ExportResult> exportOpHelper =
+ new CryptoOperationHelper<>(1, mActivity, this, R.string.progress_exporting);
+ exportOpHelper.cryptoOperation();
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java
new file mode 100644
index 000000000..b00b03ec7
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 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.util;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+
+/**
+ * used to simply transport java.net.Proxy objects created using InetSockets between services/activities
+ */
+public class ParcelableProxy implements Parcelable {
+ private String mProxyHost;
+ private int mProxyPort;
+ private Proxy.Type mProxyType;
+
+ public ParcelableProxy(String hostName, int port, Proxy.Type type) {
+ mProxyHost = hostName;
+
+ if (hostName == null) {
+ return; // represents a null proxy
+ }
+
+ mProxyPort = port;
+
+ mProxyType = type;
+ }
+
+ public static ParcelableProxy getForNoProxy() {
+ return new ParcelableProxy(null, -1, null);
+ }
+
+ public Proxy getProxy() {
+ if (mProxyHost == null) {
+ return null;
+ }
+
+ return new Proxy(mProxyType, new InetSocketAddress(mProxyHost, mProxyPort));
+ }
+
+ protected ParcelableProxy(Parcel in) {
+ mProxyHost = in.readString();
+ mProxyPort = in.readInt();
+ mProxyType = (Proxy.Type) in.readSerializable();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mProxyHost);
+ dest.writeInt(mProxyPort);
+ dest.writeSerializable(mProxyType);
+ }
+
+ @SuppressWarnings("unused")
+ public static final Parcelable.Creator<ParcelableProxy> CREATOR = new Parcelable.Creator<ParcelableProxy>() {
+ @Override
+ public ParcelableProxy createFromParcel(Parcel in) {
+ return new ParcelableProxy(in);
+ }
+
+ @Override
+ public ParcelableProxy[] newArray(int size) {
+ return new ParcelableProxy[size];
+ }
+ };
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java
index 06efdde4d..fe42c7a2c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java
@@ -117,6 +117,13 @@ public class Passphrase implements Parcelable {
}
}
+ /**
+ * Creates a new String from the char[]. This is considered unsafe!
+ */
+ public String toStringUnsafe() {
+ return new String(mPassphrase);
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -127,11 +134,7 @@ public class Passphrase implements Parcelable {
}
Passphrase that = (Passphrase) o;
- if (!Arrays.equals(mPassphrase, that.mPassphrase)) {
- return false;
- }
-
- return true;
+ return Arrays.equals(mPassphrase, that.mPassphrase);
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
index a5b0088c0..0596b0079 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
@@ -21,9 +21,13 @@ package org.sufficientlysecure.keychain.util;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.preference.PreferenceManager;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.Pref;
+import org.sufficientlysecure.keychain.R;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;
@@ -35,6 +39,10 @@ import java.util.Vector;
public class Preferences {
private static Preferences sPreferences;
private SharedPreferences mSharedPreferences;
+ private Resources mResources;
+
+ private static String PREF_FILE_NAME = "APG.main";
+ private static int PREF_FILE_MODE = Context.MODE_MULTI_PROCESS;
public static synchronized Preferences getPreferences(Context context) {
return getPreferences(context, false);
@@ -51,12 +59,18 @@ public class Preferences {
}
private Preferences(Context context) {
+ mResources = context.getResources();
updateSharedPreferences(context);
}
+ public static void setPreferenceManagerFileAndMode(PreferenceManager manager) {
+ manager.setSharedPreferencesName(PREF_FILE_NAME);
+ manager.setSharedPreferencesMode(PREF_FILE_MODE);
+ }
+
public void updateSharedPreferences(Context context) {
// multi-process safe preferences
- mSharedPreferences = context.getSharedPreferences("APG.main", Context.MODE_MULTI_PROCESS);
+ mSharedPreferences = context.getSharedPreferences(PREF_FILE_NAME, PREF_FILE_MODE);
}
public String getLanguage() {
@@ -138,6 +152,9 @@ public class Preferences {
public String[] getKeyServers() {
String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS,
Constants.Defaults.KEY_SERVERS);
+ if (rawData.equals("")) {
+ return new String[0];
+ }
Vector<String> servers = new Vector<>();
String chunks[] = rawData.split(",");
for (String c : chunks) {
@@ -150,7 +167,8 @@ public class Preferences {
}
public String getPreferredKeyserver() {
- return getKeyServers()[0];
+ String[] keyservers = getKeyServers();
+ return keyservers.length == 0 ? null : keyservers[0];
}
public void setKeyServers(String[] value) {
@@ -202,7 +220,15 @@ public class Preferences {
return mSharedPreferences.getBoolean(Pref.TEXT_USE_COMPRESSION, true);
}
+ public String getTheme() {
+ return mSharedPreferences.getString(Pref.THEME, Pref.Theme.LIGHT);
+ }
+ public void setTheme(String value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putString(Constants.Pref.THEME, value);
+ editor.commit();
+ }
public void setUseArmor(boolean useArmor) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
@@ -224,6 +250,89 @@ public class Preferences {
return mSharedPreferences.getBoolean(Pref.ENCRYPT_FILENAMES, true);
}
+ // proxy preference functions start here
+
+ public boolean getUseNormalProxy() {
+ return mSharedPreferences.getBoolean(Constants.Pref.USE_NORMAL_PROXY, false);
+ }
+
+ public boolean getUseTorProxy() {
+ return mSharedPreferences.getBoolean(Constants.Pref.USE_TOR_PROXY, false);
+ }
+
+ public String getProxyHost() {
+ return mSharedPreferences.getString(Constants.Pref.PROXY_HOST, null);
+ }
+
+ /**
+ * we store port as String for easy interfacing with EditTextPreference, but return it as an integer
+ *
+ * @return port number of proxy
+ */
+ public int getProxyPort() {
+ return Integer.parseInt(mSharedPreferences.getString(Pref.PROXY_PORT, "-1"));
+ }
+
+ /**
+ * we store port as String for easy interfacing with EditTextPreference, but return it as an integer
+ *
+ * @param port proxy port
+ */
+ public void setProxyPort(String port) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putString(Pref.PROXY_PORT, port);
+ editor.commit();
+ }
+
+ public Proxy.Type getProxyType() {
+ final String typeHttp = mResources.getString(R.string.pref_proxy_type_value_http);
+ final String typeSocks = mResources.getString(R.string.pref_proxy_type_value_socks);
+
+ String type = mSharedPreferences.getString(Pref.PROXY_TYPE, typeHttp);
+
+ if (type.equals(typeHttp)) return Proxy.Type.HTTP;
+ else if (type.equals(typeSocks)) return Proxy.Type.SOCKS;
+ else { // shouldn't happen
+ Log.e(Constants.TAG, "Invalid Proxy Type in preferences");
+ return null;
+ }
+ }
+
+ public ProxyPrefs getProxyPrefs() {
+ boolean useTor = getUseTorProxy();
+ boolean useNormalProxy = getUseNormalProxy();
+
+ if (useTor) {
+ return new ProxyPrefs(true, false, Constants.Orbot.PROXY_HOST, Constants.Orbot.PROXY_PORT,
+ Constants.Orbot.PROXY_TYPE);
+ } else if (useNormalProxy) {
+ return new ProxyPrefs(useTor, useNormalProxy, getProxyHost(), getProxyPort(), getProxyType());
+ } else {
+ return new ProxyPrefs(false, false, null, -1, null);
+ }
+ }
+
+ public static class ProxyPrefs {
+ public final ParcelableProxy parcelableProxy;
+ public final boolean torEnabled;
+ public final boolean normalPorxyEnabled;
+
+ /**
+ * torEnabled and normalProxyEnabled are not expected to both be true
+ *
+ * @param torEnabled if Tor is to be used
+ * @param normalPorxyEnabled if user-specified proxy is to be used
+ */
+ public ProxyPrefs(boolean torEnabled, boolean normalPorxyEnabled, String hostName, int port, Proxy.Type type) {
+ this.torEnabled = torEnabled;
+ this.normalPorxyEnabled = normalPorxyEnabled;
+ if (!torEnabled && !normalPorxyEnabled) this.parcelableProxy = new ParcelableProxy(null, -1, null);
+ else this.parcelableProxy = new ParcelableProxy(hostName, port, type);
+ }
+ }
+
+ // proxy preference functions ends here
+
public CloudSearchPrefs getCloudSearchPrefs() {
return new CloudSearchPrefs(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true),
mSharedPreferences.getBoolean(Pref.SEARCH_KEYBASE, true),
@@ -247,7 +356,7 @@ public class Preferences {
}
}
- public void updatePreferences() {
+ public void upgradePreferences() {
if (mSharedPreferences.getInt(Constants.Pref.PREF_DEFAULT_VERSION, 0) !=
Constants.Defaults.PREF_VERSION) {
switch (mSharedPreferences.getInt(Constants.Pref.PREF_DEFAULT_VERSION, 0)) {
@@ -281,6 +390,10 @@ public class Preferences {
}
// fall through
case 4: {
+ setTheme(Constants.Pref.Theme.DEFAULT);
+ }
+ // fall through
+ case 5: {
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java
index 4ff14e3bb..d1d1ada2a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java
@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.util;
import android.content.res.AssetManager;
+import com.squareup.okhttp.OkHttpClient;
import org.sufficientlysecure.keychain.Constants;
import java.io.ByteArrayInputStream;
@@ -26,7 +27,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
-import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -61,7 +61,7 @@ public class TlsHelper {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int reads = is.read();
- while(reads != -1){
+ while (reads != -1) {
baos.write(reads);
reads = is.read();
}
@@ -74,15 +74,56 @@ public class TlsHelper {
}
}
- public static URLConnection openConnection(URL url) throws IOException, TlsHelperException {
+ public static void pinCertificateIfNecessary(OkHttpClient client, URL url) throws TlsHelperException, IOException {
if (url.getProtocol().equals("https")) {
for (String domain : sStaticCA.keySet()) {
if (url.getHost().endsWith(domain)) {
- return openCAConnection(sStaticCA.get(domain), url);
+ pinCertificate(sStaticCA.get(domain), client);
}
}
}
- return url.openConnection();
+ }
+
+ /**
+ * Modifies the client to accept only requests with a given certificate. Applies to all URLs requested by the
+ * client.
+ * Therefore a client that is pinned this way should be used to only make requests to URLs with passed certificate.
+ * TODO: Refactor - More like SSH StrictHostKeyChecking than pinning?
+ *
+ * @param certificate certificate to pin
+ * @param client OkHttpClient to enforce pinning on
+ * @throws TlsHelperException
+ * @throws IOException
+ */
+ private static void pinCertificate(byte[] certificate, OkHttpClient client)
+ throws TlsHelperException, IOException {
+ // We don't use OkHttp's CertificatePinner since it depends on a TrustManager to verify it too. Refer to
+ // note at end of description: http://square.github.io/okhttp/javadoc/com/squareup/okhttp/CertificatePinner.html
+ // Creating our own TrustManager that trusts only our certificate eliminates the need for certificate pinning
+ try {
+ // Load CA
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ Certificate ca = cf.generateCertificate(new ByteArrayInputStream(certificate));
+
+ // Create a KeyStore containing our trusted CAs
+ String keyStoreType = KeyStore.getDefaultType();
+ KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+ keyStore.load(null, null);
+ keyStore.setCertificateEntry("ca", ca);
+
+ // Create a TrustManager that trusts the CAs in our KeyStore
+ String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
+ tmf.init(keyStore);
+
+ // Create an SSLContext that uses our TrustManager
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, tmf.getTrustManagers(), null);
+
+ client.setSslSocketFactory(context.getSocketFactory());
+ } catch (CertificateException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) {
+ throw new TlsHelperException(e);
+ }
}
/**
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java
new file mode 100644
index 000000000..9eb92f92f
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java
@@ -0,0 +1,252 @@
+/* This is the license for Orlib, a free software project to
+ provide anonymity on the Internet from a Google Android smartphone.
+
+ For more information about Orlib, see https://guardianproject.info/
+
+ If you got this file as a part of a larger bundle, there may be other
+ license terms that you should be aware of.
+ ===============================================================================
+ Orlib is distributed under this license (aka the 3-clause BSD license)
+
+ Copyright (c) 2009-2010, Nathan Freitas, The Guardian Project
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ *****
+ Orlib contains a binary distribution of the JSocks library:
+ http://code.google.com/p/jsocks-mirror/
+ which is licensed under the GNU Lesser General Public License:
+ http://www.gnu.org/licenses/lgpl.html
+
+ *****
+*/
+
+package org.sufficientlysecure.keychain.util.orbot;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.dialog.SupportInstallDialogFragment;
+import org.sufficientlysecure.keychain.ui.dialog.OrbotStartDialogFragment;
+import org.sufficientlysecure.keychain.ui.dialog.PreferenceInstallDialogFragment;
+import org.sufficientlysecure.keychain.util.Preferences;
+
+/**
+ * This class is taken from the NetCipher library: https://github.com/guardianproject/NetCipher/
+ */
+public class OrbotHelper {
+
+ public final static String ORBOT_PACKAGE_NAME = "org.torproject.android";
+ public final static String TOR_BIN_PATH = "/data/data/org.torproject.android/app_bin/tor";
+
+ public final static String ACTION_START_TOR = "org.torproject.android.START_TOR";
+
+ public static boolean isOrbotRunning() {
+ int procId = TorServiceUtils.findProcessId(TOR_BIN_PATH);
+
+ return (procId != -1);
+ }
+
+ public static boolean isOrbotInstalled(Context context) {
+ return isAppInstalled(ORBOT_PACKAGE_NAME, context);
+ }
+
+ private static boolean isAppInstalled(String uri, Context context) {
+ PackageManager pm = context.getPackageManager();
+
+ boolean installed;
+ try {
+ pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
+ installed = true;
+ } catch (PackageManager.NameNotFoundException e) {
+ installed = false;
+ }
+ return installed;
+ }
+
+ /**
+ * hack to get around the fact that PreferenceActivity still supports only android.app.DialogFragment
+ *
+ * @return
+ */
+ public static android.app.DialogFragment getPreferenceInstallDialogFragment() {
+ return PreferenceInstallDialogFragment.newInstance(R.string.orbot_install_dialog_title,
+ R.string.orbot_install_dialog_content, ORBOT_PACKAGE_NAME);
+ }
+
+ public static DialogFragment getInstallDialogFragment() {
+ return SupportInstallDialogFragment.newInstance(R.string.orbot_install_dialog_title,
+ R.string.orbot_install_dialog_content, ORBOT_PACKAGE_NAME);
+ }
+
+ public static DialogFragment getInstallDialogFragmentWithThirdButton(Messenger messenger, int middleButton) {
+ return SupportInstallDialogFragment.newInstance(messenger, R.string.orbot_install_dialog_title,
+ R.string.orbot_install_dialog_content, ORBOT_PACKAGE_NAME, middleButton, true);
+ }
+
+ public static DialogFragment getOrbotStartDialogFragment(Messenger messenger, int middleButton) {
+ return OrbotStartDialogFragment.newInstance(messenger, R.string.orbot_start_dialog_title, R.string
+ .orbot_start_dialog_content,
+ middleButton);
+ }
+
+ public static Intent getOrbotStartIntent() {
+ Intent intent = new Intent(ACTION_START_TOR);
+ intent.setPackage(ORBOT_PACKAGE_NAME);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
+
+ /**
+ * checks preferences to see if Orbot is required, and if yes, if it is installed and running
+ *
+ * @param context used to retrieve preferences
+ * @return false if Tor is selected proxy and Orbot is not installed or running, true
+ * otherwise
+ */
+ public static boolean isOrbotInRequiredState(Context context) {
+ Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(context).getProxyPrefs();
+ if (!proxyPrefs.torEnabled) {
+ return true;
+ } else if (!OrbotHelper.isOrbotInstalled(context) || !OrbotHelper.isOrbotRunning()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * checks if Tor is enabled and if it is, that Orbot is installed and runnign. Generates appropriate dialogs.
+ *
+ * @param middleButton resourceId of string to display as the middle button of install and enable dialogs
+ * @param middleButtonRunnable runnable to be executed if the user clicks on the middle button
+ * @param proxyPrefs
+ * @param fragmentActivity
+ * @return true if Tor is not enabled or Tor is enabled and Orbot is installed and running, else false
+ */
+ public static boolean putOrbotInRequiredState(final int middleButton,
+ final Runnable middleButtonRunnable,
+ final Runnable dialogDismissRunnable,
+ Preferences.ProxyPrefs proxyPrefs,
+ FragmentActivity fragmentActivity) {
+
+ if (!proxyPrefs.torEnabled) {
+ return true;
+ }
+
+ if (!OrbotHelper.isOrbotInstalled(fragmentActivity)) {
+ Handler ignoreTorHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SupportInstallDialogFragment.MESSAGE_MIDDLE_CLICKED:
+ middleButtonRunnable.run();
+ break;
+ case SupportInstallDialogFragment.MESSAGE_DIALOG_DISMISSED:
+ dialogDismissRunnable.run();
+ break;
+ }
+ }
+ };
+
+ OrbotHelper.getInstallDialogFragmentWithThirdButton(
+ new Messenger(ignoreTorHandler),
+ middleButton
+ ).show(fragmentActivity.getSupportFragmentManager(), "OrbotHelperOrbotInstallDialog");
+
+ return false;
+ } else if (!OrbotHelper.isOrbotRunning()) {
+
+ Handler ignoreTorHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case OrbotStartDialogFragment.MESSAGE_MIDDLE_BUTTON:
+ middleButtonRunnable.run();
+ break;
+ case OrbotStartDialogFragment.MESSAGE_DIALOG_DISMISSED:
+ dialogDismissRunnable.run();
+ break;
+ }
+ }
+ };
+
+ OrbotHelper.getOrbotStartDialogFragment(new Messenger(ignoreTorHandler),
+ middleButton)
+ .show(fragmentActivity.getSupportFragmentManager(), "OrbotHelperOrbotStartDialog");
+
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public static boolean putOrbotInRequiredState(final int middleButton,
+ final Runnable middleButtonRunnable,
+ Preferences.ProxyPrefs proxyPrefs,
+ FragmentActivity fragmentActivity) {
+ Runnable emptyRunnable = new Runnable() {
+ @Override
+ public void run() {
+
+ }
+ };
+ return putOrbotInRequiredState(middleButton, middleButtonRunnable, emptyRunnable,
+ proxyPrefs, fragmentActivity);
+ }
+
+ /**
+ * generates a standard Orbot install/enable dialog if necessary, based on proxy settings in
+ * preferences
+ *
+ * @param ignoreTorRunnable run when the "Ignore Tor" button is pressed
+ * @param fragmentActivity used to start the activ
+ * @return
+ */
+ public static boolean putOrbotInRequiredState(Runnable ignoreTorRunnable,
+ FragmentActivity fragmentActivity) {
+ return putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTorRunnable,
+ Preferences.getPreferences(fragmentActivity).getProxyPrefs(), fragmentActivity);
+ }
+
+ public static boolean putOrbotInRequiredState(Runnable ignoreTorRunnable,
+ Runnable dismissDialogRunnable,
+ FragmentActivity fragmentActivity) {
+ return putOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTorRunnable,
+ dismissDialogRunnable,
+ Preferences.getPreferences(fragmentActivity).getProxyPrefs(),
+ fragmentActivity);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/TorServiceUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/TorServiceUtils.java
new file mode 100644
index 000000000..d11e80f7a
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/TorServiceUtils.java
@@ -0,0 +1,144 @@
+/* This is the license for Orlib, a free software project to
+ provide anonymity on the Internet from a Google Android smartphone.
+
+ For more information about Orlib, see https://guardianproject.info/
+
+ If you got this file as a part of a larger bundle, there may be other
+ license terms that you should be aware of.
+ ===============================================================================
+ Orlib is distributed under this license (aka the 3-clause BSD license)
+
+ Copyright (c) 2009-2010, Nathan Freitas, The Guardian Project
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ *****
+ Orlib contains a binary distribution of the JSocks library:
+ http://code.google.com/p/jsocks-mirror/
+ which is licensed under the GNU Lesser General Public License:
+ http://www.gnu.org/licenses/lgpl.html
+
+ *****
+*/
+
+package org.sufficientlysecure.keychain.util.orbot;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.net.URLEncoder;
+import java.util.StringTokenizer;
+
+/**
+ * This class is taken from the NetCipher library: https://github.com/guardianproject/NetCipher/
+ */
+public class TorServiceUtils {
+ // various console cmds
+ public final static String SHELL_CMD_PS = "ps";
+ public final static String SHELL_CMD_PIDOF = "pidof";
+
+ public static int findProcessId(String command) {
+ int procId = -1;
+
+ try {
+ procId = findProcessIdWithPidOf(command);
+
+ if (procId == -1) {
+ procId = findProcessIdWithPS(command);
+ }
+ } catch (Exception e) {
+ try {
+ procId = findProcessIdWithPS(command);
+ } catch (Exception e2) {
+ Log.e(Constants.TAG, "Unable to get proc id for command: " + URLEncoder.encode(command), e2);
+ }
+ }
+
+ return procId;
+ }
+
+ // use 'pidof' command
+ public static int findProcessIdWithPidOf(String command) throws Exception {
+
+ int procId = -1;
+ Runtime r = Runtime.getRuntime();
+ Process procPs;
+
+ String baseName = new File(command).getName();
+ // fix contributed my mikos on 2010.12.10
+ procPs = r.exec(new String[]{
+ SHELL_CMD_PIDOF, baseName
+ });
+ // procPs = r.exec(SHELL_CMD_PIDOF);
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
+ String line;
+
+ while ((line = reader.readLine()) != null) {
+
+ try {
+ // this line should just be the process id
+ procId = Integer.parseInt(line.trim());
+ break;
+ } catch (NumberFormatException e) {
+ Log.e("TorServiceUtils", "unable to parse process pid: " + line, e);
+ }
+ }
+
+ return procId;
+ }
+
+ // use 'ps' command
+ public static int findProcessIdWithPS(String command) throws Exception {
+ int procId = -1;
+ Runtime r = Runtime.getRuntime();
+ Process procPs;
+
+ procPs = r.exec(SHELL_CMD_PS);
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.contains(' ' + command)) {
+
+ StringTokenizer st = new StringTokenizer(line, " ");
+ st.nextToken(); // proc owner
+
+ procId = Integer.parseInt(st.nextToken().trim());
+
+ break;
+ }
+ }
+
+ return procId;
+ }
+}
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_add_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_add_white_24dp.png
new file mode 100644
index 000000000..694179bd4
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_add_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.png
index 37931a0ad..d9a5ebedf 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_apps_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png
index 5fa494878..a2051cef9 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_check_circle_black_48dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_circle_black_48dp.png
new file mode 100644
index 000000000..1c2ddcd5f
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_circle_black_48dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.png
index f42a0e2d2..729f29010 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_close_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_close_black_24dp.png
index d5a928783..1a9cd75a0 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_close_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_close_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.png
index 0fd15563a..ceb1a1eeb 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_close_white_24dp.png
Binary files differ
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
index dc8c85cce..9a9e5706f 100644
--- 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
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_delete_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_delete_white_24dp.png
new file mode 100644
index 000000000..4a9f76947
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_delete_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.png
index 35e3b426f..57139a78a 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.png
index ed993f35d..9625f148f 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_folder_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_folder_white_24dp.png
index 9f5c75609..02ea533a8 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_folder_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_folder_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_help_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_help_black_24dp.png
index 05be749c3..374fafd7f 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_help_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_help_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_black_24dp.png
index 0888c6173..de5029591 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_white_24dp.png
index b94735ecb..cd4f04aa1 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_mode_edit_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_mode_edit_white_24dp.png
index 3ee3e1720..595ff10ac 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_mode_edit_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_mode_edit_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
index 164385d04..57c9fa546 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png
index cd16fdd50..ffa7be933 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_reorder_grey_500_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_reorder_grey_500_24dp.png
new file mode 100644
index 000000000..58fe2c52e
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_reorder_grey_500_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_repeat_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_repeat_white_24dp.png
index 612e73458..81c5be793 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_repeat_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_repeat_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_save_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_save_white_24dp.png
index 8c9e9cec0..dd3f10664 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_save_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_save_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_search_white_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_search_white_24dp.png
index a2fc5b2e7..bbfbc96cb 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_search_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_settings_black_24dp.png
index b16209fc1..acf1ddf85 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_settings_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_settings_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
index 2839b1352..20ba48063 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/uid_mail_bad.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_retyped_bad.png
index dc20b0f03..dc20b0f03 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/uid_mail_bad.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_retyped_bad.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/uid_mail_ok.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_retyped_ok.png
index 76944469c..76944469c 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/uid_mail_ok.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_retyped_ok.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.png
index c900b8ec7..e05e76ffc 100644
--- a/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_vpn_key_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_add_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_add_white_24dp.png
new file mode 100644
index 000000000..3856041d7
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_add_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.png
index 5b1fd7766..aaadd5c46 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_apps_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png
index 9e662f6d4..d571552fb 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_check_circle_black_48dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_circle_black_48dp.png
new file mode 100644
index 000000000..86bf38e98
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_circle_black_48dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.png
index e91f9048b..dfcb55d02 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_close_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_close_black_24dp.png
index 4ebf8a227..40a1a84e3 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_close_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_close_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_24dp.png
index e80681aeb..af7f8288d 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_close_white_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
index 4ad9e552d..c94cc28f1 100644
--- 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
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_delete_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_delete_white_24dp.png
new file mode 100644
index 000000000..e2f5f3555
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_delete_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.png
index a5ab2c5d3..08c16a328 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.png
index 73fc3b422..feb85a775 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_folder_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_folder_white_24dp.png
index 1c5797c9e..831d723ba 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_folder_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_folder_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_help_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_help_black_24dp.png
index f3743dc20..f6e789ba1 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_help_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_help_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_black_24dp.png
index d18d4b667..3a4a1586e 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_white_24dp.png
index 381b6a118..1127f87f7 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_mode_edit_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_mode_edit_white_24dp.png
index 85cff0b91..12b09f1d9 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_mode_edit_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_mode_edit_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png
index 8d1e433a5..c61e948bb 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png
index 235c84f1e..97e42b525 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_reorder_grey_500_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_reorder_grey_500_24dp.png
new file mode 100644
index 000000000..d6abf0936
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_reorder_grey_500_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_repeat_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_repeat_white_24dp.png
index 8a2b641ca..b1c2e04ab 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_repeat_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_repeat_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_save_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_save_white_24dp.png
index bb26bc075..015062ed3 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_save_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_save_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_search_white_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_search_white_24dp.png
index dff1e3a8a..faefc59c8 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_search_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_settings_black_24dp.png
index 3405c951d..c59419c02 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_settings_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_settings_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
index f0ff945b8..f02d360aa 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/uid_mail_bad.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_retyped_bad.png
index 262d53027..262d53027 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/uid_mail_bad.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_retyped_bad.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/uid_mail_ok.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_retyped_ok.png
index e16ec810a..e16ec810a 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/uid_mail_ok.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_retyped_ok.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.png
index 5e8781731..f7ac2a184 100644
--- a/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_vpn_key_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_add_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_add_white_24dp.png
new file mode 100644
index 000000000..67bb598e5
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_add_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.png
index c8187799b..22f12110e 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_apps_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png
index addbfc886..ce5b878b0 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_circle_black_48dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_circle_black_48dp.png
new file mode 100644
index 000000000..872b578c8
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_circle_black_48dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.png
index e5024472a..3b2b65d26 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_black_24dp.png
index ed2b2525f..6bc437298 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_24dp.png
index 76e07f097..b7c7ffd0e 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_close_white_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
index c6f0e6b85..1cf76a960 100644
--- 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
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png
new file mode 100644
index 000000000..388b5b060
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_delete_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.png
index 47c7b52a1..323360ead 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.png
index 45d30d999..d3ee65e9a 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_folder_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_folder_white_24dp.png
index e5f54cef0..71a5a137c 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_folder_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_folder_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_help_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_help_black_24dp.png
index 87095ef26..d3542c6bc 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_help_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_help_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_black_24dp.png
index 8856c70df..2a166945a 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_white_24dp.png
index c5e9d0b49..ad8d91a99 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_mode_edit_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_mode_edit_white_24dp.png
index 7f0ea51bf..5a06bff5a 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_mode_edit_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_mode_edit_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
index a55d19922..a3c80e73d 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png
index 5f89fc257..1989184b1 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_reorder_grey_500_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_reorder_grey_500_24dp.png
new file mode 100644
index 000000000..0af0cb76d
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_reorder_grey_500_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_repeat_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_repeat_white_24dp.png
index 729220066..ad8b8c0df 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_repeat_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_repeat_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_save_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_save_white_24dp.png
index aa0332092..adda09575 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_save_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_save_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_search_white_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_search_white_24dp.png
index 043759acd..bfc3e3939 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_search_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_black_24dp.png
index 2b775b646..e84e188a1 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_settings_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
index 4b3675766..81c80b700 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/uid_mail_bad.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_retyped_bad.png
index fc7ba24a3..fc7ba24a3 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/uid_mail_bad.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_retyped_bad.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/uid_mail_ok.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_retyped_ok.png
index e2aef1177..e2aef1177 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/uid_mail_ok.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_retyped_ok.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.png
index ccbdce4ab..a8761c90a 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_vpn_key_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png
new file mode 100644
index 000000000..0fdced8fc
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.png
index 626543b47..6d0fe2c00 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_apps_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png
index 4057cc545..746d77579 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_circle_black_48dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_circle_black_48dp.png
new file mode 100644
index 000000000..6d3b6449c
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_circle_black_48dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png
index 6e03d54cf..2c2ad771f 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_black_24dp.png
index 08f59ea1e..51b4401ca 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png
index 0eb9d8b08..6b717e0dd 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_close_white_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
index 081fbec5b..074ea8807 100644
--- 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
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png
new file mode 100644
index 000000000..3fcdfdb55
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.png
index 0470e3f02..ee92f4ecd 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.png
index aadd04af6..5cd142c1d 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_folder_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_folder_white_24dp.png
index 0d1ac4876..b93d5a1e4 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_folder_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_folder_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_help_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_help_black_24dp.png
index f32d7e708..645822e83 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_help_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_help_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_black_24dp.png
index c49d420e0..a7caa2db8 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png
index 0dcada814..0e52c7c75 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_mode_edit_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_mode_edit_white_24dp.png
index 34ec7092f..02e19d045 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_mode_edit_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_mode_edit_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
index 043acd808..547ef30aa 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png
index 72128fe69..1692d8a24 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_reorder_grey_500_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_reorder_grey_500_24dp.png
new file mode 100644
index 000000000..1d9c88d10
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_reorder_grey_500_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_repeat_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_repeat_white_24dp.png
index 63f8de50f..5de7a2951 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_repeat_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_repeat_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_save_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_save_white_24dp.png
index 6c87e1358..3e0ce1a5f 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_save_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_save_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png
index 0bbeab150..abbb98951 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png
index 47f0e0d82..3023ff8da 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_settings_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
index 09d4df6af..784933ad5 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/uid_mail_bad.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_retyped_bad.png
index bc71d3a65..bc71d3a65 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/uid_mail_bad.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_retyped_bad.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/uid_mail_ok.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_retyped_ok.png
index 501a75d63..501a75d63 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/uid_mail_ok.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_retyped_ok.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.png
index 736bde37a..16b1e4e24 100644
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_vpn_key_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png
new file mode 100644
index 000000000..d64c22e9e
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.png
index d12d2e796..bfbe789c3 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_apps_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png
index 02f2f6fe8..fb06e1d48 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_circle_black_48dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_circle_black_48dp.png
new file mode 100644
index 000000000..0e3b23964
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_circle_black_48dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png
index 87892840e..d670618c7 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_black_24dp.png
index c5d79caff..df42feecb 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png
index 7b2a480a0..396419219 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_close_white_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
index 04c07fb56..1f6af72d0 100644
--- 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
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png
new file mode 100644
index 000000000..8d322aa9b
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_delete_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png
index 08ae54533..99c6e3e1c 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png
index 228b2a982..ad852e3e6 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_folder_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_folder_white_24dp.png
index 7a3c198ee..a1afbe9da 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_folder_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_folder_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_help_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_help_black_24dp.png
index a4286b54c..7c4823055 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_help_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_help_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_black_24dp.png
index db080df4e..e66dd967d 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.png
index a70c55b7e..a55147be1 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_lock_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_24dp.png
index 9380370f4..d6668a051 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png
index 7cc008475..be5c062b5 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png
index d271d8e03..f5beca251 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_repeat_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_repeat_white_24dp.png
index f3c284330..c7f3072ee 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_repeat_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_repeat_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_save_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_save_white_24dp.png
index 51998492c..bd80bf1f7 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_save_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_save_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png
index 70c21baf7..dd5adfc7f 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_black_24dp.png
index bce161d00..476d5c978 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_settings_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
index 0fe15fc05..5a8544ce5 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_share_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.png
index 3451d9855..f04166536 100644
--- a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.png
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_vpn_key_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable/cardview_header.xml b/OpenKeychain/src/main/res/drawable/cardview_header.xml
index 9bab96ea9..ff08f9fe3 100644
--- a/OpenKeychain/src/main/res/drawable/cardview_header.xml
+++ b/OpenKeychain/src/main/res/drawable/cardview_header.xml
@@ -6,6 +6,6 @@
android:height="1dp"
android:width="1000dp" />
- <solid android:color="@color/bg_gray" />
+ <solid android:color="?attr/colorCardViewHeaderDivider" />
-</shape> \ No newline at end of file
+</shape>
diff --git a/OpenKeychain/src/main/res/drawable/fab_label_background.xml b/OpenKeychain/src/main/res/drawable/fab_label_background.xml
index 0d8c05b11..aa5e0a88e 100644
--- a/OpenKeychain/src/main/res/drawable/fab_label_background.xml
+++ b/OpenKeychain/src/main/res/drawable/fab_label_background.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/black_semi_transparent"/>
+ <solid android:color="?attr/colorFabBackground"/>
<padding
android:left="16dp"
android:top="4dp"
@@ -8,4 +8,4 @@
android:bottom="4dp"/>
<corners
android:radius="2dp"/>
-</shape> \ No newline at end of file
+</shape>
diff --git a/OpenKeychain/src/main/res/drawable/section_header.xml b/OpenKeychain/src/main/res/drawable/section_header.xml
index 04d3d4957..4bee8049b 100644
--- a/OpenKeychain/src/main/res/drawable/section_header.xml
+++ b/OpenKeychain/src/main/res/drawable/section_header.xml
@@ -6,6 +6,6 @@
android:height="2dp"
android:width="1000dp" />
- <solid android:color="@color/header_text" />
+ <solid android:color="?attr/colorHeaderText" />
-</shape> \ No newline at end of file
+</shape>
diff --git a/OpenKeychain/src/main/res/drawable/selector_transparent_button.xml b/OpenKeychain/src/main/res/drawable/selector_transparent_button.xml
deleted file mode 100644
index ed856f281..000000000
--- a/OpenKeychain/src/main/res/drawable/selector_transparent_button.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- Borderless Buttons for API < 11, see http://stackoverflow.com/a/14663170 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:drawable="@color/bg_gray" />
- <item android:drawable="@android:color/transparent" />
-</selector> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/drawable/yubikey_phone.png b/OpenKeychain/src/main/res/drawable/yubikey_phone.png
index 6a03501c6..3cdfbba0f 100644
--- a/OpenKeychain/src/main/res/drawable/yubikey_phone.png
+++ b/OpenKeychain/src/main/res/drawable/yubikey_phone.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml
index ffb7493f6..b3969a2bd 100644
--- a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml
@@ -29,7 +29,7 @@
android:id="@+id/add_user_id_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textColor="@color/tertiary_text_light"
+ android:textColor="?attr/colorTertiaryText"
android:singleLine="true"
android:lines="1"
android:maxLines="1"
diff --git a/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml b/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml
index c3f6e33cb..ea20b77b3 100644
--- a/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml
+++ b/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml
@@ -117,7 +117,7 @@
android:layout_height="wrap_content"
android:elevation="4dp"
fab:fab_icon="@drawable/ic_play_arrow_white_24dp"
- fab:fab_colorNormal="@color/fab"
- fab:fab_colorPressed="@color/fab_pressed" />
+ fab:fab_colorNormal="?attr/colorFab"
+ fab:fab_colorPressed="?attr/colorFabPressed" />
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml b/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml
index 1ea0a520d..20abb3965 100644
--- a/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/api_app_settings_fragment.xml
@@ -53,11 +53,11 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/api_settings_package_signature"
+ android:text="@string/api_settings_package_certificate"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
- android:id="@+id/api_app_settings_package_signature"
+ android:id="@+id/api_app_settings_package_certificate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Base64 encoded hash of signature"
diff --git a/OpenKeychain/src/main/res/layout/backup_fragment.xml b/OpenKeychain/src/main/res/layout/backup_fragment.xml
new file mode 100644
index 000000000..96fba954b
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/backup_fragment.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="24dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dip"
+ android:text="@string/backup_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/backup_section" />
+
+ <TextView
+ android:id="@+id/backup_all"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:drawablePadding="8dp"
+ android:drawableRight="@drawable/ic_save_grey_24dp"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:text="@string/backup_all"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/backup_public_keys"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:drawablePadding="8dp"
+ android:drawableRight="@drawable/ic_save_grey_24dp"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:text="@string/backup_public_keys"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginBottom="8dp"
+ android:background="?android:attr/listDivider" />
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml b/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml
index 9b6b35012..bd7b00823 100644
--- a/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml
@@ -28,7 +28,7 @@
android:id="@+id/certify_fingerprint_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:cardBackgroundColor="@android:color/white"
+ app:cardBackgroundColor="?attr/colorCardViewBackground"
app:cardUseCompatPadding="true"
app:cardCornerRadius="4dp"
android:layout_gravity="top">
@@ -151,4 +151,4 @@
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml
index 17cfe54ac..d4ece38ac 100644
--- a/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml
@@ -51,7 +51,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
@@ -88,4 +88,4 @@
android:clickable="true"
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
index e085fcb09..9a6c33f82 100644
--- a/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
@@ -28,7 +28,7 @@
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:text="@string/label_name"
- android:textColor="@color/tertiary_text_light"
+ android:textColor="?attr/colorTertiaryText"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
@@ -44,7 +44,7 @@
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:text="@string/label_email"
- android:textColor="@color/tertiary_text_light"
+ android:textColor="?attr/colorTertiaryText"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
@@ -87,7 +87,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/create_key_rsa"
- android:textColor="@color/android_green_light"
+ android:textColor="?attr/colorPrimary"
android:textAppearance="?android:attr/textAppearanceMedium"
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
@@ -129,7 +129,7 @@
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:text="@string/create_key_final_robot_text"
- android:textColor="@color/android_green_light"
+ android:textColor="?attr/colorPrimary"
android:textAppearance="?android:attr/textAppearanceMedium"
android:drawableLeft="@drawable/create_key_robot"
android:drawablePadding="8dp" />
@@ -144,7 +144,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
@@ -182,4 +182,4 @@
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml
index a2f81f74c..7b8ba3fc1 100644
--- a/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml
@@ -45,7 +45,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
@@ -82,4 +82,4 @@
android:clickable="true"
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
index abfb2861b..9d10bbe70 100644
--- a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
@@ -64,7 +64,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
@@ -101,4 +101,4 @@
android:clickable="true"
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
index 2db147475..20c434c02 100644
--- a/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
@@ -30,7 +30,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml
index 864e3aecf..ca203d0b5 100644
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml
@@ -34,7 +34,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
@@ -73,4 +73,4 @@
style="?android:attr/borderlessButtonStyle"
android:layout_gravity="center_vertical" />
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml
index e70188e49..838ee37b4 100644
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml
@@ -84,7 +84,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
@@ -123,4 +123,4 @@
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml
new file mode 100644
index 000000000..393ec76d4
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml
@@ -0,0 +1,109 @@
+<?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:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:layout_above="@+id/create_key_buttons">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/create_key_yubi_key_pin_text" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/create_key_yubi_key_pin" />
+
+ <TextView
+ android:id="@+id/create_yubi_key_pin"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ tools:text="123456" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/create_key_yubi_key_admin_pin" />
+
+ <TextView
+ android:id="@+id/create_yubi_key_admin_pin"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ tools:text="12345678" />
+
+ </LinearLayout>
+ </ScrollView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:background="?attr/colorButtonRow"
+ android:id="@+id/create_key_buttons">
+
+ <TextView
+ android:id="@+id/create_key_back_button"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/btn_back"
+ android:textAllCaps="true"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="left|center_vertical"
+ android:clickable="true"
+ style="?android:attr/borderlessButtonStyle" />
+
+ <TextView
+ android:id="@+id/create_key_next_button"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/btn_next"
+ android:textAllCaps="true"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="right|center_vertical"
+ android:clickable="true"
+ style="?android:attr/borderlessButtonStyle" />
+ </LinearLayout>
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml
new file mode 100644
index 000000000..d233398ca
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_above="@+id/create_key_buttons"
+ android:fillViewport="true">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/create_key_yubi_key_pin_repeat_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/create_key_yubi_key_pin"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <EditText
+ android:id="@+id/create_yubi_key_pin_repeat"
+ 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/create_key_yubi_key_pin_repeat"
+ android:inputType="numberPassword" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/create_key_yubi_key_admin_pin"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <EditText
+ android:id="@+id/create_yubi_key_admin_pin_repeat"
+ 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/create_key_yubi_key_admin_pin_repeat"
+ android:inputType="numberPassword" />
+
+ </LinearLayout>
+ </ScrollView>
+
+ <LinearLayout
+ android:id="@+id/create_key_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:background="?attr/colorButtonRow"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/create_key_back_button"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="left|center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/btn_back"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/create_key_next_button"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:drawablePadding="8dp"
+ android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
+ android:gravity="right|center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/btn_next"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ </LinearLayout>
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml
index 4e4b53118..a000dc82e 100644
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml
@@ -40,7 +40,7 @@
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:id="@+id/create_key_buttons">
<TextView
@@ -79,4 +79,4 @@
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml b/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml
index d58542e62..048595dd8 100644
--- a/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml
+++ b/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml
@@ -7,7 +7,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
- custom:cardBackgroundColor="@android:color/white"
+ custom:cardBackgroundColor="?attr/colorCardViewBackground"
custom:cardElevation="2dp"
custom:cardUseCompatPadding="true"
custom:cardCornerRadius="4dp"
@@ -286,6 +286,38 @@
</LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_gravity="center_vertical"
+ android:drawablePadding="12dp"
+ android:text="@string/msg_cancelled"
+ android:drawableLeft="@drawable/status_signature_invalid_cutout_24dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+
+ <ImageView
+ android:id="@+id/cancel_retry"
+ android:scaleType="center"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:clickable="true"
+ android:padding="6dp"
+ android:background="?android:selectableItemBackground"
+ android:src="@drawable/ic_repeat_grey_24dp"
+ android:layout_gravity="center_vertical" />
+
+ </LinearLayout>
+
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
-</android.support.v7.widget.CardView> \ No newline at end of file
+</android.support.v7.widget.CardView>
diff --git a/OpenKeychain/src/main/res/layout/del_rev_dialog.xml b/OpenKeychain/src/main/res/layout/del_rev_dialog.xml
new file mode 100644
index 000000000..053f98627
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/del_rev_dialog.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/del_rev_dialog_message"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+ android:layout_marginBottom="16dp"/>
+
+ <Spinner
+ android:id="@+id/spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:drawSelectorOnTop="true"
+ android:entries="@array/rev_del_dialog_entries"/>
+
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/drawer_custom_header.xml b/OpenKeychain/src/main/res/layout/drawer_custom_header.xml
deleted file mode 100644
index 86465db98..000000000
--- a/OpenKeychain/src/main/res/layout/drawer_custom_header.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?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:gravity="center"
- android:background="@color/primary">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/app_name"
- android:textColor="@color/white"
- android:layout_gravity="center_horizontal" />
-</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml
index 394f14a34..7bd919abc 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml
@@ -1,120 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- android:paddingTop="4dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <TextView
- style="@style/SectionHeader"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:text="@string/section_encrypt" />
-
- <TextView
- android:id="@+id/encrypt_files"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:text="@string/btn_encrypt_files"
- android:drawableRight="@drawable/ic_folder_grey_24dp"
- android:drawablePadding="8dp"
- android:gravity="center_vertical" />
+ android:paddingTop="4dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="vertical"
+ >
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider" />
-
- <TextView
- android:id="@+id/encrypt_text"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:text="@string/btn_encrypt_text"
- android:drawableRight="@drawable/ic_comment_text_grey600_24dp"
- android:drawablePadding="8dp"
- android:gravity="center_vertical" />
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/section_encrypt" />
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider" />
+ <TextView
+ android:id="@+id/encrypt_files"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ style="?android:attr/borderlessButtonStyle"
+ android:text="@string/btn_encrypt_files"
+ android:drawableRight="@drawable/ic_folder_grey_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical" />
- <TextView
- style="@style/SectionHeader"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:text="@string/section_decrypt" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
- <TextView
- android:id="@+id/decrypt_files"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:text="@string/btn_decrypt_files"
- android:drawableRight="@drawable/ic_folder_grey_24dp"
- android:drawablePadding="8dp"
- android:gravity="center_vertical" />
+ <TextView
+ android:id="@+id/encrypt_text"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ style="?android:attr/borderlessButtonStyle"
+ android:text="@string/btn_encrypt_text"
+ android:drawableRight="@drawable/ic_comment_text_grey600_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical" />
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
- <LinearLayout
- android:id="@+id/decrypt_from_clipboard"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:orientation="horizontal"
- android:paddingLeft="8dp"
- android:paddingRight="0dp"
- tools:ignore="UseCompoundDrawables">
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/section_decrypt" />
<TextView
+ android:id="@+id/decrypt_files"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical"
- android:text="@string/btn_decrypt_clipboard" />
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ style="?android:attr/borderlessButtonStyle"
+ android:text="@string/btn_decrypt_files"
+ android:drawableRight="@drawable/ic_folder_grey_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical" />
- <ImageView
- android:id="@+id/clipboard_icon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:padding="8dp"
- android:src="@drawable/ic_content_paste_grey_24dp"
- android:layout_gravity="center_vertical" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
- </LinearLayout>
+ <LinearLayout
+ android:id="@+id/decrypt_from_clipboard"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ style="?android:attr/borderlessButtonStyle"
+ android:orientation="horizontal"
+ android:paddingLeft="8dp"
+ android:paddingRight="0dp"
+ tools:ignore="UseCompoundDrawables">
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider"
- android:layout_marginBottom="8dp" />
+ <TextView
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:text="@string/btn_decrypt_clipboard" />
+
+ <ImageView
+ android:id="@+id/clipboard_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:padding="8dp"
+ android:src="@drawable/ic_content_paste_grey_24dp"
+ android:layout_gravity="center_vertical" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider"
+ android:layout_marginBottom="8dp" />
+ </LinearLayout>
-</LinearLayout> \ No newline at end of file
+</ScrollView>
diff --git a/OpenKeychain/src/main/res/layout/file_list_entry.xml b/OpenKeychain/src/main/res/layout/file_list_entry.xml
index 7f0e1e89e..e1b03f8ae 100644
--- a/OpenKeychain/src/main/res/layout/file_list_entry.xml
+++ b/OpenKeychain/src/main/res/layout/file_list_entry.xml
@@ -55,4 +55,4 @@
android:clickable="true"
android:layout_centerVertical="true"
android:background="?android:selectableItemBackground" />
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml
index 773a9d416..a7b1e6a53 100644
--- a/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml
+++ b/OpenKeychain/src/main/res/layout/foldable_linearlayout.xml
@@ -25,7 +25,7 @@
android:layout_height="wrap_content"
android:text="@string/none"
android:layout_gravity="center_vertical"
- android:textColor="@color/header_text" />
+ android:textColor="?attr/colorHeaderText" />
</LinearLayout>
<LinearLayout
@@ -34,4 +34,4 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/help_about_fragment.xml b/OpenKeychain/src/main/res/layout/help_about_fragment.xml
index 6afab2e12..dbcd97bfd 100644
--- a/OpenKeychain/src/main/res/layout/help_about_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/help_about_fragment.xml
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent"
+ android:paddingBottom="0dp"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp"
+ android:paddingTop="0dp">
<LinearLayout
android:layout_width="match_parent"
@@ -11,17 +15,17 @@
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
- android:scrollbars="vertical" >
+ android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal" >
+ android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:orientation="vertical" >
+ android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
@@ -34,7 +38,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical" >
+ android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
@@ -51,12 +55,13 @@
</LinearLayout>
</LinearLayout>
- <org.sufficientlysecure.htmltextview.HtmlTextView
+ <org.sufficientlysecure.htmltextview.HtmlTextView
android:id="@+id/help_about_text"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="16dp"
android:textAppearance="@android:style/TextAppearance.Small" />
</LinearLayout>
-</ScrollView> \ No newline at end of file
+</ScrollView>
diff --git a/OpenKeychain/src/main/res/layout/import_keys_activity.xml b/OpenKeychain/src/main/res/layout/import_keys_activity.xml
index 332b95ce5..28bb8a0b8 100644
--- a/OpenKeychain/src/main/res/layout/import_keys_activity.xml
+++ b/OpenKeychain/src/main/res/layout/import_keys_activity.xml
@@ -25,21 +25,11 @@
android:id="@+id/import_keys_top_container"
android:layout_width="match_parent"
android:layout_height="64dp"
- android:orientation="vertical"
- android:background="@android:color/white" />
+ android:orientation="vertical" />
<View
android:layout_width="match_parent"
- android:layout_height="2dip"
- android:background="?android:attr/listDivider" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="16dp" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="2dip"
+ android:layout_height="1dip"
android:background="?android:attr/listDivider" />
<FrameLayout
@@ -47,22 +37,18 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
- android:layout_weight="1"
- android:background="@android:color/white" />
+ android:layout_weight="1" />
<RelativeLayout
android:id="@+id/import_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:background="@android:color/white">
+ android:orientation="vertical">
<View
android:id="@+id/import_divider"
android:layout_width="match_parent"
android:layout_height="1dip"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
android:background="?android:attr/listDivider" />
<TextView
@@ -91,4 +77,4 @@
</RelativeLayout>
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/key_list_content.xml b/OpenKeychain/src/main/res/layout/key_list_content.xml
index bd0239da7..146367082 100644
--- a/OpenKeychain/src/main/res/layout/key_list_content.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_content.xml
@@ -23,7 +23,7 @@
<!--<LinearLayout
android:orientation="vertical"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:layout_width="match_parent"
android:layout_height="wrap_content">
diff --git a/OpenKeychain/src/main/res/layout/key_list_fragment.xml b/OpenKeychain/src/main/res/layout/key_list_fragment.xml
index ea3426f90..9c41590db 100644
--- a/OpenKeychain/src/main/res/layout/key_list_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_fragment.xml
@@ -45,8 +45,8 @@
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
- fab:fab_addButtonColorNormal="@color/primary"
- fab:fab_addButtonColorPressed="@color/primary_dark"
+ fab:fab_addButtonColorNormal="?attr/colorPrimary"
+ fab:fab_addButtonColorPressed="?attr/colorPrimaryDark"
fab:fab_addButtonSize="normal"
fab:fab_addButtonPlusIconColor="@color/icons"
fab:fab_expandDirection="up"
@@ -61,8 +61,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
fab:fab_icon="@drawable/ic_qrcode_white_24dp"
- fab:fab_colorNormal="@color/primary"
- fab:fab_colorPressed="@color/primary_dark"
+ fab:fab_colorNormal="?attr/colorPrimary"
+ fab:fab_colorPressed="?attr/colorPrimaryDark"
fab:fab_title="Scan QR Code"
fab:fab_size="mini" />
@@ -71,8 +71,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
fab:fab_icon="@drawable/ic_cloud_search_24dp"
- fab:fab_colorNormal="@color/primary"
- fab:fab_colorPressed="@color/primary_dark"
+ fab:fab_colorNormal="?attr/colorPrimary"
+ fab:fab_colorPressed="?attr/colorPrimaryDark"
fab:fab_title="Search Cloud"
fab:fab_size="mini" />
@@ -81,10 +81,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
fab:fab_icon="@drawable/ic_folder_white_24dp"
- fab:fab_colorNormal="@color/primary"
- fab:fab_colorPressed="@color/primary_dark"
+ fab:fab_colorNormal="?attr/colorPrimary"
+ fab:fab_colorPressed="?attr/colorPrimaryDark"
fab:fab_title="Import from File"
fab:fab_size="mini" />
</com.getbase.floatingactionbutton.FloatingActionsMenu>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/key_server_preference.xml b/OpenKeychain/src/main/res/layout/key_server_preference.xml
index 5319a3ec0..570d57d9b 100644
--- a/OpenKeychain/src/main/res/layout/key_server_preference.xml
+++ b/OpenKeychain/src/main/res/layout/key_server_preference.xml
@@ -1,94 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<include
android:id="@+id/toolbar_include"
layout="@layout/toolbar_standalone" />
- <LinearLayout
- android:layout_below="@id/toolbar_include"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/text_layout"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:orientation="horizontal">
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_marginBottom="6sp"
- android:layout_marginLeft="16sp"
- android:layout_marginRight="6sp"
- android:layout_marginTop="6sp"
- android:layout_weight="1"
- android:background="@android:drawable/menuitem_background"
- android:orientation="vertical"
- android:focusable="true">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <TextView
- android:id="@+id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
-
- <Button
- android:id="@+id/rotate"
- android:layout_width="wrap_content"
- android:layout_height="31dp"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="4dip"
- android:layout_marginRight="6dip"
- android:text="rotate"
- android:textColor="#ffffffff"
- android:textStyle="bold"
- android:background="@drawable/button_rounded_blue" />
-
- <ImageButton
- android:id="@+id/add"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_margin="10dp"
- android:src="@drawable/plus"
- android:background="@drawable/button_rounded_green" />
- </LinearLayout>
-
- <View
- android:id="@+id/separator"
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider" />
-
- <ScrollView
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/editors"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" />
- </ScrollView>
-
- </LinearLayout>
-
-</RelativeLayout> \ No newline at end of file
+ <TextView
+ android:layout_marginLeft="6sp"
+ android:layout_marginRight="6sp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="@string/label_keyservers_title"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6sp"
+ android:layout_marginRight="6sp"
+ android:layout_marginBottom="6sp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/label_keyserver_settings_hint"/>
+
+ <View
+ style="@style/Divider"/>
+
+ <FrameLayout
+ android:id="@+id/keyserver_settings_fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/log_display_item.xml b/OpenKeychain/src/main/res/layout/log_display_item.xml
index d35413185..25249003f 100644
--- a/OpenKeychain/src/main/res/layout/log_display_item.xml
+++ b/OpenKeychain/src/main/res/layout/log_display_item.xml
@@ -15,7 +15,7 @@
android:layout_height="match_parent"
android:id="@+id/log_img"
android:minWidth="10dp"
- android:background="@color/bg_gray" />
+ android:background="?attr/colorLogBackground" />
<TextView
android:layout_width="0dp"
@@ -53,7 +53,7 @@
android:layout_height="match_parent"
android:id="@+id/log_second_img"
android:minWidth="10dp"
- android:background="@color/bg_gray" />
+ android:background="?attr/colorLogBackground" />
<TextView
android:layout_width="0dp"
@@ -67,4 +67,4 @@
android:layout_gravity="center_vertical"/>
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/nfc_activity.xml b/OpenKeychain/src/main/res/layout/nfc_activity.xml
deleted file mode 100644
index 9acd0676c..000000000
--- a/OpenKeychain/src/main/res/layout/nfc_activity.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <include
- android:id="@+id/toolbar_include"
- layout="@layout/toolbar_standalone" />
-
- <LinearLayout
- android:layout_below="@id/toolbar_include"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp">
-
- <TextView
- android:text="@string/nfc_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@android:style/TextAppearance.Large"
- android:id="@+id/nfc_text"
- android:gravity="center"
- android:layout_gravity="center" />
-
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:src="@drawable/yubikey_phone" />
-
- </LinearLayout>
-</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/nfc_operation_activity.xml b/OpenKeychain/src/main/res/layout/nfc_operation_activity.xml
new file mode 100644
index 000000000..8b043861f
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/nfc_operation_activity.xml
@@ -0,0 +1,179 @@
+<?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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/view_animator"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:animateLayoutChanges="true"
+ android:inAnimation="@anim/fade_in"
+ android:measureAllChildren="false"
+ android:minHeight="?listPreferredItemHeightSmall"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="3">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/nfc_activity_0_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
+ android:layout_marginTop="24dp"
+ android:text="@string/nfc_text"
+ android:textAppearance="@android:style/TextAppearance.Medium" />
+
+ <ImageView
+ android:id="@+id/nfc_activity_0_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/nfc_activity_0_text"
+ android:layout_margin="24dp"
+ android:adjustViewBounds="true"
+ android:background="@android:color/transparent"
+ android:src="@drawable/yubikey_phone" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/nfc_activity_1_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
+ android:layout_marginTop="24dp"
+ android:text="@string/nfc_wait"
+ android:textAppearance="@android:style/TextAppearance.Medium" />
+
+ <ProgressBar
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:padding="8dp" />
+
+ <!-- placeholder to retain dialog size -->
+ <ImageView
+ android:id="@+id/nfc_activity_1_placeholder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/nfc_activity_1_text"
+ android:layout_margin="24dp"
+ android:adjustViewBounds="true"
+ android:background="@android:color/transparent"
+ android:src="@drawable/yubikey_phone"
+ android:visibility="invisible" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/nfc_activity_2_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
+ android:layout_marginTop="24dp"
+ android:text="@string/nfc_finished"
+ android:textAppearance="@android:style/TextAppearance.Medium" />
+
+ <!-- placeholder to retain dialog size -->
+ <ImageView
+ android:id="@+id/nfc_activity_2_placeholder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/nfc_activity_2_text"
+ android:layout_margin="24dp"
+ android:adjustViewBounds="true"
+ android:background="@android:color/transparent"
+ android:src="@drawable/yubikey_phone"
+ android:visibility="invisible" />
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:adjustViewBounds="true"
+ android:background="@android:color/transparent"
+ android:src="@drawable/ic_check_circle_black_48dp" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/nfc_activity_3_text_placeholder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignEnd="@+id/nfc_activity_3_placeholder"
+ android:layout_alignRight="@+id/nfc_activity_3_placeholder"
+ android:layout_marginLeft="24dp"
+ android:layout_marginTop="24dp"
+ android:text=""
+ android:textAppearance="@android:style/TextAppearance.Medium" />
+
+ <!-- placeholder to retain dialog size -->
+ <ImageView
+ android:id="@+id/nfc_activity_3_placeholder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/nfc_activity_3_text_placeholder"
+ android:layout_margin="24dp"
+ android:adjustViewBounds="true"
+ android:background="@android:color/transparent"
+ android:src="@drawable/yubikey_phone"
+ android:visibility="invisible" />
+
+ <TextView
+ android:id="@+id/nfc_activity_3_error_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:layout_margin="24dp"
+ android:textAppearance="@android:style/TextAppearance.Medium"
+ android:textColor="@color/android_red_dark"
+ tools:text="Error text" />
+
+ <Button
+ android:id="@+id/nfc_activity_3_error_try_again"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/nfc_activity_3_placeholder"
+ android:layout_margin="8dp"
+ android:text="@string/error_nfc_try_again"
+ android:textColor="@color/accent" />
+
+ </RelativeLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+</LinearLayout> \ 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 ffc5266b5..9ce8f01fa 100644
--- a/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/passphrase_repeat_dialog.xml
@@ -40,9 +40,9 @@
android:layout_gravity="end|center_vertical"
custom:strength="medium"
custom:showGuides="false"
- custom:color_fail="@color/android_red_light"
- custom:color_weak="@color/android_orange_light"
- custom:color_strong="@color/android_green_light" />
+ custom:color_fail="@color/password_strength_low"
+ custom:color_weak="@color/password_strength_medium"
+ custom:color_strong="@color/password_strength_high" />
</FrameLayout>
@@ -57,4 +57,4 @@
android:ems="10"
android:layout_gravity="center_horizontal" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml b/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml
index a9e86057c..2b39cf54c 100644
--- a/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml
+++ b/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml
@@ -60,4 +60,4 @@
tools:src="@drawable/status_signature_revoked_cutout_24dp"
/>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/settings_keyserver_fragment.xml b/OpenKeychain/src/main/res/layout/settings_keyserver_fragment.xml
new file mode 100644
index 000000000..57c81a433
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/settings_keyserver_fragment.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<android.support.v7.widget.RecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyserver_recycler_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" /> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/settings_keyserver_item.xml b/OpenKeychain/src/main/res/layout/settings_keyserver_item.xml
new file mode 100644
index 000000000..338104bda
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/settings_keyserver_item.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/outer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?listPreferredItemHeight">
+
+ <LinearLayout
+ android:id="@+id/keyserver_layout"
+ android:padding="6sp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@+id/drag_handle"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/selected_keyserver_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/label_selected_keyserver_title"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:visibility="gone"/>
+
+ <TextView
+ android:id="@+id/keyserver_tv"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/drag_handle"
+ android:layout_width="?listPreferredItemHeight"
+ android:layout_height="?listPreferredItemHeight"
+ android:scaleType="center"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/ic_reorder_grey_500_24dp" />
+
+ <View
+ android:layout_alignParentBottom="true"
+ style="@style/Divider"/>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml b/OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml
index 4f9b5d373..1afa76b60 100644
--- a/OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml
+++ b/OpenKeychain/src/main/res/layout/toolbar_result_decrypt.xml
@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/toolbar_include"
android:elevation="4dp"
- android:background="@color/white"
+ android:background="?attr/colorBrightToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
diff --git a/OpenKeychain/src/main/res/layout/toolbar_standalone_white.xml b/OpenKeychain/src/main/res/layout/toolbar_standalone_white.xml
index d4269c2ba..8fddfe4ba 100644
--- a/OpenKeychain/src/main/res/layout/toolbar_standalone_white.xml
+++ b/OpenKeychain/src/main/res/layout/toolbar_standalone_white.xml
@@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar_include"
android:elevation="4dp"
- android:background="@color/white"
+ android:background="?attr/colorBrightToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
diff --git a/OpenKeychain/src/main/res/layout/toolbar_tabs.xml b/OpenKeychain/src/main/res/layout/toolbar_tabs.xml
index 91efda682..ed42ef52e 100644
--- a/OpenKeychain/src/main/res/layout/toolbar_tabs.xml
+++ b/OpenKeychain/src/main/res/layout/toolbar_tabs.xml
@@ -17,8 +17,8 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
- android:textColor="@color/tab_text"
- app:pstsTextColorSelected="@color/tab_text_selected"
- app:pstsIndicatorColor="@color/tab_indicator" />
+ android:textColor="?attr/colorTabText"
+ app:pstsTextColorSelected="?attr/colorTabTextSelected"
+ app:pstsIndicatorColor="?attr/colorTabIndicator" />
</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/view_key_activity.xml b/OpenKeychain/src/main/res/layout/view_key_activity.xml
index b3f4e721d..8e04f6899 100644
--- a/OpenKeychain/src/main/res/layout/view_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_activity.xml
@@ -75,7 +75,7 @@
android:layout_marginEnd="48dp"
android:text=""
tools:text="My Key"
- android:textColor="@color/tab_text"
+ android:textColor="?attr/colorTabText"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_above="@+id/toolbar2" />
@@ -200,7 +200,7 @@
tools:visibility="visible"
android:elevation="4dp"
fab:fab_icon="@drawable/ic_qrcode_white_24dp"
- fab:fab_colorNormal="@color/fab"
- fab:fab_colorPressed="@color/fab_pressed" />
+ fab:fab_colorNormal="?attr/colorFab"
+ fab:fab_colorPressed="?attr/colorFabPressed" />
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_certs_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_adv_certs_fragment.xml
index d512477aa..3b9215d50 100644
--- a/OpenKeychain/src/main/res/layout/view_key_adv_certs_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_adv_certs_fragment.xml
@@ -10,7 +10,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:padding="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/certs_text"
@@ -45,4 +45,4 @@
</FrameLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml
index b6679524f..eecb19000 100644
--- a/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml
@@ -7,7 +7,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@color/holo_gray_bright"
+ android:background="?attr/colorButtonRow"
android:padding="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/key_trust_header_text"
@@ -123,4 +123,4 @@
</LinearLayout>
</ScrollView>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
index c08d66cc1..d82506e74 100644
--- a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
@@ -126,6 +126,23 @@
android:background="?android:attr/listDivider" />
<ImageButton
+ android:id="@+id/view_key_action_key_export"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:padding="8dp"
+ android:src="@drawable/ic_save_grey_24dp"
+ android:layout_gravity="center_vertical"
+ android:background="?android:selectableItemBackground" />
+
+ <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" />
+
+ <ImageButton
android:id="@+id/view_key_action_key_nfc"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_user_id_item.xml b/OpenKeychain/src/main/res/layout/view_key_adv_user_id_item.xml
index 1c55a1446..a9ebe43d3 100644
--- a/OpenKeychain/src/main/res/layout/view_key_adv_user_id_item.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_adv_user_id_item.xml
@@ -34,7 +34,7 @@
android:id="@+id/user_id_item_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textColor="@color/tertiary_text_light"
+ android:textColor="?attr/colorTertiaryText"
android:text="comment"
android:textAppearance="?android:attr/textAppearanceSmall" />
diff --git a/OpenKeychain/src/main/res/layout/view_key_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_fragment.xml
index a71eb5880..8c1023427 100644
--- a/OpenKeychain/src/main/res/layout/view_key_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_fragment.xml
@@ -17,7 +17,7 @@
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- card_view:cardBackgroundColor="@android:color/white"
+ card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="4dp">
@@ -47,7 +47,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
- card_view:cardBackgroundColor="@android:color/white"
+ card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="4dp">
diff --git a/OpenKeychain/src/main/res/layout/view_key_yubikey.xml b/OpenKeychain/src/main/res/layout/view_key_yubikey.xml
index 83272ef4e..57f93493d 100644
--- a/OpenKeychain/src/main/res/layout/view_key_yubikey.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_yubikey.xml
@@ -18,7 +18,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:transitionName="card"
- card_view:cardBackgroundColor="@android:color/white"
+ card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="4dp"
diff --git a/OpenKeychain/src/main/res/menu/key_list.xml b/OpenKeychain/src/main/res/menu/key_list.xml
index c4797d5f7..d3a2bd0fd 100644
--- a/OpenKeychain/src/main/res/menu/key_list.xml
+++ b/OpenKeychain/src/main/res/menu/key_list.xml
@@ -10,11 +10,6 @@
app:showAsAction="collapseActionView|always" />
<item
- android:id="@+id/menu_key_list_export"
- android:title="@string/menu_export_all_keys"
- app:showAsAction="never" />
-
- <item
android:id="@+id/menu_key_list_create"
android:title="@string/menu_manage_keys"
app:showAsAction="never" />
diff --git a/OpenKeychain/src/main/res/menu/key_list_multi.xml b/OpenKeychain/src/main/res/menu/key_list_multi.xml
index 7fdf4a5c1..26bc9f98f 100644
--- a/OpenKeychain/src/main/res/menu/key_list_multi.xml
+++ b/OpenKeychain/src/main/res/menu/key_list_multi.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:tools="http://schemas.android.com/tools"
- xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/menu_key_list_multi_encrypt"
@@ -8,21 +8,8 @@
android:title="@string/menu_encrypt_to" />
<item
- android:id="@+id/menu_key_list_multi_export"
- android:showAsAction="never"
- tools:ignore="AppCompatResource"
- android:title="@string/menu_export_key" />
-
- <item
android:id="@+id/menu_key_list_multi_delete"
- android:showAsAction="never"
- tools:ignore="AppCompatResource"
+ android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/menu_delete_key" />
- <item
- android:id="@+id/menu_key_list_multi_select_all"
- android:showAsAction="never"
- tools:ignore="AppCompatResource"
- android:title="@string/menu_select_all" />
-
</menu>
diff --git a/OpenKeychain/src/main/res/menu/keyserver_pref_menu.xml b/OpenKeychain/src/main/res/menu/keyserver_pref_menu.xml
new file mode 100644
index 000000000..c4002a682
--- /dev/null
+++ b/OpenKeychain/src/main/res/menu/keyserver_pref_menu.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/menu_add_keyserver"
+ android:title="@string/menu_search"
+ android:icon="@drawable/ic_add_white_24dp"
+ app:showAsAction="always" />
+</menu> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/raw-ar/help_changelog.md b/OpenKeychain/src/main/res/raw-ar/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-ar/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-ar/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-bg/help_changelog.md b/OpenKeychain/src/main/res/raw-bg/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-bg/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-bg/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-cs/help_changelog.md b/OpenKeychain/src/main/res/raw-cs/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-cs/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-de/help_changelog.md b/OpenKeychain/src/main/res/raw-de/help_changelog.md
index 8b845a6b2..80551b8d7 100644
--- a/OpenKeychain/src/main/res/raw-de/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-de/help_changelog.md
@@ -1,11 +1,16 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
- * New decryption screen
- * Decryption of multiple files at once
- * Better handling of YubiKey errors
+ * Neuer Entschlüsselungsbildschirm
+ * Entschlüsselung mehrerer Dateien gleichzeitig
+ * Bessere Behandlung von YubiKey-Fehlern
## 3.2
@@ -81,37 +86,37 @@
* Experimental YubiKey support: Preference to allow other PINs, currently only signing via the OpenPGP API works, not inside of OpenKeychain
* Nutzung gekürzter Schlüssel repariert
* Standardmäßig SHA256 aufgrund von Kompatibilität
- * Intent API has changed, see https://github.com/open-keychain/open-keychain/wiki/Intent-API
- * OpenPGP API now handles revoked/expired keys and returns all user ids
+ * Intent-API hat sich geändert, siehe https://github.com/open-keychain/open-keychain/wiki/Intent-API
+ * OpenPGP-API bearbeitet ab jetzt widerrufene/abgelaufene Schlüssel und gibt alle Benutzer-IDs zurück
## 2.9
- * Fixing crashes introduced in v2.8
+ * Behebt Abstürze aus v2.8
* Experimentelle ECC-Unterstützung
- * Experimental YubiKey support: Only signing with imported keys
+ * Experimentelle YubiKey-Unterstützung (nur Unterschreiben mit importierten Schlüsseln)
## 2.8
- * So many bugs have been fixed in this release that we focus on the main new features
- * Key edit: awesome new design, key revocation
- * Key import: awesome new design, secure keyserver connections via hkps, keyserver resolving via DNS SRV records
+ * In diesem Release wurden so viele Fehler behoben, dass wir uns lieber auf die neuen Funktionen konzentrieren
+ * Schlüsselbearbeitung: Fantastisches neues Design, Schlüsselwiderruf
+ * Schlüsselimport: Fantastisches neues Design, sichere Verbindungen zu Keyservern über hkps, Namensauflösung der Schlüsselserver über DNS SRV-Einträge
* Neuer Bildschirm bei der ersten Öffnung
- * New key creation screen: autocompletion of name and email based on your personal Android accounts
- * File encryption: awesome new design, support for encrypting multiple files
- * New icons to show status of key (by Brennan Novak)
- * Important bug fix: Importing of large key collections from a file is now possible
- * Notification showing cached passphrases
- * Keys are connected to Android's contacts
+ * Neuer Schlüsselerstellungsbildschirm: Autovervollständigung von Name und E-Mail basierend auf Deinen persönlichen Android-Konten
+ * Dateiverschlüsselung: fantastisches neues Design, Unterstützung für die Verschlüsselung mehrerer Dateien
+ * Neue Symbile zum Anzeigen des Schlüsselstatus (von Brennan Novak)
+ * Wichtiger Fehler behoben: Import großer Schlüsselsammlungen aus einer Datei ist nun möglich
+ * Benachrichtigung, die zwischengespeicherte Passwörter anzeigt
+ * Schlüssel sind mit den Kontakten verbunden
-This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray, Thialfihar
+Dieser Release wäre ohne die Arbeit von Vincent Breitmoser (GSoC 2014), mar-v-in (GSoC 2014), Daniel Albert, Art O Cathain, Daniel Haß, Tim Bray und Thialfihar nicht möglich gewesen
## 2.7
* Lila! (Dominik, Vincent)
- * New key view design (Dominik, Vincent)
- * New flat Android buttons (Dominik, Vincent)
+ * Neues Schlüsselansichtsdesign (Dominik, Vincent)
+ * Neue flache Android-Knöpfe (Dominik, Vincent)
* API-Korrekturen (Dominik)
* Import aus keybase.io (Tim Bray)
@@ -123,28 +128,28 @@ This release wouldn't be possible without the work of Vincent Breitmoser (GSoC 2
## 2.6
- * Key certifications (thanks to Vincent Breitmoser)
- * Support for GnuPG partial secret keys (thanks to Vincent Breitmoser)
- * New design for signature verification
+ * Schlüsselbeglaubigungen (dank Vincent Breitmoser)
+ * Unterstützung für GnuPG-Teilschlüssel (danke an Vincent Breitmoser)
+ * Neues Design für Signaturprüfung
* Benutzerdefinierte Schlüssellänge (Dank an Greg Witczak)
- * Fix share-functionality from other apps
+ * Fehler bei der Teilen-Funktionalität aus anderen Apps behoben
## 2.5
- * Fix decryption of symmetric OpenPGP messages/files
- * Refactored key edit screen (thanks to Ash Hughes)
- * New modern design for encrypt/decrypt screens
- * OpenPGP API version 3 (multiple api accounts, internal fixes, key lookup)
+ * Fehler bei der Entschlüsselung symmetrischer OpenPGP-Nachrichten/Dateien behoben
+ * Umgestaltung des Schlüsselbearbeitungsbildschirms (Dank an Ash Hughes)
+ * Neues modernes Design für Verschlüsselungs-/Entschlüsselungsbildschirme
+ * OpenPGP-API Version 3 (mehrere API-Konten, interne Fehlerbehebungen, Schlüsselsuche)
## 2.4
-Thanks to all applicants of Google Summer of Code 2014 who made this release feature rich and bug free!
-Besides several small patches, a notable number of patches are made by the following people (in alphabetical order):
+Dank an alle Bewerber bei Google Summer of Code 2014, welche diesen Release funktionsreich und fehlerfrei gemacht haben!
+Neben einigen kleinen Fehlerbehebungen wurden bemerkenswert viele Patches durch die folgenden Personen beigesteuert (alphabetisch sortiert):
Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.
- * New unified key list
- * Colorized key fingerprint
+ * Neue einheitliche Schlüsselliste
+ * Eingefärbter Schlüsselfingerabdruck
* Support for keyserver ports
* Deactivate possibility to generate weak keys
* Much more internal work on the API
diff --git a/OpenKeychain/src/main/res/raw-es/help_about.md b/OpenKeychain/src/main/res/raw-es/help_about.md
index de39a8146..fdf0e7063 100644
--- a/OpenKeychain/src/main/res/raw-es/help_about.md
+++ b/OpenKeychain/src/main/res/raw-es/help_about.md
@@ -57,7 +57,7 @@ Licencia: GPLv3+
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Licencia Apache v2)
* [ZXing](https://github.com/zxing/zxing) (Licencia Apache v2)
* [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Licencia Apache v2)
- * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
+ * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Licencia Apache v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Licencia Apache v2)
* [Snackbar](https://github.com/nispok/snackbar) (Licencia MIT)
* [FloatingActionButton](https://github.com/futuresimple/android-floating-action-button) (Licencia Apache v2)
diff --git a/OpenKeychain/src/main/res/raw-es/help_changelog.md b/OpenKeychain/src/main/res/raw-es/help_changelog.md
index 087392cdf..909a95fa9 100644
--- a/OpenKeychain/src/main/res/raw-es/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-es/help_changelog.md
@@ -1,11 +1,16 @@
[//]: # (NOTA: ¡Por favor ponga cada frase en su propia línea, Transifex pone cada línea en su propio campo de traducción!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
- * New decryption screen
- * Decryption of multiple files at once
- * Better handling of YubiKey errors
+ * Nueva pantalla de descifrado
+ * Descifrado de múltiples ficheros a la vez
+ * Mejor manejo de errores de YubiKey
## 3.2
diff --git a/OpenKeychain/src/main/res/raw-et/help_changelog.md b/OpenKeychain/src/main/res/raw-et/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-et/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-et/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-eu/help_about.md b/OpenKeychain/src/main/res/raw-eu/help_about.md
index 06f2e3fd1..ce443f234 100644
--- a/OpenKeychain/src/main/res/raw-eu/help_about.md
+++ b/OpenKeychain/src/main/res/raw-eu/help_about.md
@@ -57,7 +57,7 @@ Baimena: GPLv3+
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache Baimena v2)
* [ZXing](https://github.com/zxing/zxing) (Apache Baimena v2)
* [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Apache Baimena v2)
- * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
+ * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Diseinua) (Apache Baimena 2 bertsioa)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache Baimena v2)
* [Snackbar](https://github.com/nispok/snackbar) (MIT Baimena)
* [FloatingActionButton](https://github.com/futuresimple/android-floating-action-button) (Apache Baimena v2)
diff --git a/OpenKeychain/src/main/res/raw-eu/help_changelog.md b/OpenKeychain/src/main/res/raw-eu/help_changelog.md
index 04771c696..f7af66c5b 100644
--- a/OpenKeychain/src/main/res/raw-eu/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-eu/help_changelog.md
@@ -1,15 +1,20 @@
[//]: # (OHARRA: Meseez jarri esaldi bakoitza bere lerroan, Transifex-ek lerroak bere itzulpen eremuan jartzen ditu!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
- * New decryption screen
- * Decryption of multiple files at once
- * Better handling of YubiKey errors
+ * Azalpen ikusleiho berria
+ * Agiri ugariren azalpena aldiberean
+ * YubiKey akatsen kudeaketa hobea
## 3.2
- * First version with full YubiKey support available from the user interface: Edit keys, bind YubiKey to keys,...
+ * Lehen bertsioa YubiKey sostengu osoarekin eskuragarri erabiltzaile interfazetik: Editatu giltzak, lotu YubiKey giltzekin,...
Material diseinua
* QR Kode eskaneatzea baterapena (Baimen berriak beharrezkoak)
* Hobetuta giltza sortze laguntzailea
@@ -55,10 +60,10 @@
## 3.0
- * Propose installable compatible apps in apps list
+ * Eskaini bateragarritasun ezegonkorreko aplikazioak aplikazio zerrendan
* Diseinu berria dekriptaketa ikusleihoentzat
* Zuzenketa ugari giltza inportatzean, zuzenduta baita ere giltzen zuriketa
- * Honor and display key authenticate flags
+ * Ohoretu eta erakutsi giltza egiaztapen ikurrak
* Erabiltzaile interfazea norbere giltzak sortzeko
* Zuzenduta erabiltzaile id ukatze egiaztagiriak
* Hodei bilaketa berria (ohiko giltza-zerbitzari eta keybase.io gain bilatzen da)
@@ -68,8 +73,8 @@
## 2.9.2
- * Fix keys broken in 2.9.1
- * Experimental YubiKey support: Decryption now working via API
+ * Zuzenduta 2.9.1-ko giltza haustea
+ * YubiKey sostengu esperimentala. Dekriptaketak orain API bidez egiten du lan
## 2.9.1
diff --git a/OpenKeychain/src/main/res/raw-fi/help_changelog.md b/OpenKeychain/src/main/res/raw-fi/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-fi/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-fi/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-fr/help_about.md b/OpenKeychain/src/main/res/raw-fr/help_about.md
index a93d250a5..0eb1e9823 100644
--- a/OpenKeychain/src/main/res/raw-fr/help_about.md
+++ b/OpenKeychain/src/main/res/raw-fr/help_about.md
@@ -57,7 +57,7 @@ Licence : GPLv3+
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Licence Apache v2)
* [ZXing](https://github.com/zxing/zxing) (Licence Apache v2)
* [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Licence Apache v2)
- * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
+ * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Conception matérielle)</a> (Licence Apache v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Licence Apache v2)
* [Snackbar](https://github.com/nispok/snackbar) (Licence MIT)
* [FloatingActionButton](https://github.com/futuresimple/android-floating-action-button) (Licence Apache v2)
diff --git a/OpenKeychain/src/main/res/raw-fr/help_changelog.md b/OpenKeychain/src/main/res/raw-fr/help_changelog.md
index c6275e322..4bbea2d1b 100644
--- a/OpenKeychain/src/main/res/raw-fr/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-fr/help_changelog.md
@@ -1,15 +1,20 @@
[//] : # (NOTE : veuillez mettre chaque phrase sur sa propre ligne. Transifex met chaque ligne dans son propre champ de traduction !)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
- * New decryption screen
- * Decryption of multiple files at once
- * Better handling of YubiKey errors
+ * Nouvel écran de déchiffrement
+ * Déchiffrement simultané de plusieurs fichiers
+ * Meilleure gestion des erreurs ClefYubi
## 3.2
- * Première version avec prise en charge complète de la clef Yubi, proposée dans l'interface utilisateur : modifier les clefs, relier la clef Yubi au clefs...
+ * Première version avec prise en charge complète de la ClefYubi, proposée dans l'interface utilisateur : modifier les clefs, relier la clef Yubi au clefs...
* Conception matérielle
* Intégration de la lecture de code QR (nouvelles permissions exigées)
* Amélioration de l'assistant de création de clef
@@ -44,7 +49,7 @@
* Écran de déchiffrement redessiné
* Nouveaux agencement et couleurs d'icônes
* Importation des clefs secrètes corrigée de Symantec Encryption Desktop
- * Prise en charge expérimentale des clefs Yubi : les ID de sous-clefs sont maintenant vérifiés correctement
+ * Prise en charge expérimentale de la ClefYubi : les ID de sous-clefs sont maintenant vérifiés correctement
## 3.0.1
@@ -63,13 +68,13 @@
* Corrigé - Certificats de révocation des ID utilisateurs
* Nouvelle recherche nuagique (dans les serveurs traditionnels et dans keybase.io)
* Prise en charge du dépouillement des clefs dans OpenKeychain
- * Prise en charge expérimentale des clefs Yubi : prise en charge de la génération de signature et le déchiffrement
+ * Prise en charge expérimentale de la ClefYubi : prise en charge de la génération de signature et le déchiffrement
## 2.9.2
* Correctif - Clefs brisées dans 2.9.1
- * Prise en charge expérimentale des clefs Yubi : le déchiffrement fonctionne maintenant avec l'API
+ * Prise en charge expérimentale de la ClefYubi : le déchiffrement fonctionne maintenant avec l'API
## 2.9.1
@@ -78,7 +83,7 @@
* Correctif - Gestion des drapeaux de clefs (prend maintenant en charge les clefs Mailvelope 0.7)
* Gestion des phrases de passe améliorée
* Partage de clefs par SafeSlinger
- * Prise en charge expérimentale des clefs Yubi : préférence pour permettre d'autres NIP, seule la signature par l'API OpenPGP fonctionne actuellement, mais pas dans OpenKeychain
+ * Prise en charge expérimentale de la ClefYubi : préférence pour permettre d'autres NIP, seule la signature par l'API OpenPGP fonctionne actuellement, mais pas dans OpenKeychain
* Correctif - Utilisation de clefs dépouillées
* SHA256 par défaut pour la compatibilité
* L'API des intentions a changé, voir https://github.com/open-keychain/open-keychain/wiki/Intent-API
@@ -89,7 +94,7 @@
* Correction des plantages présents dans v2.8
* Prise en charge expérimentale CCE
- * Prise en charge expérimentale des clefs Yubi : signature seulement avec les clefs importées
+ * Prise en charge expérimentale de la ClefYubi : signature seulement avec les clefs importées
## 2.8
diff --git a/OpenKeychain/src/main/res/raw-is/help_changelog.md b/OpenKeychain/src/main/res/raw-is/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-is/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-is/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-it/help_about.md b/OpenKeychain/src/main/res/raw-it/help_about.md
index 844fb51ca..d69eaaf89 100644
--- a/OpenKeychain/src/main/res/raw-it/help_about.md
+++ b/OpenKeychain/src/main/res/raw-it/help_about.md
@@ -57,7 +57,7 @@ Licenza: GPLv3+
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
* [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Apache License v2)
- * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
+ * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Design materiale) (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)
diff --git a/OpenKeychain/src/main/res/raw-it/help_changelog.md b/OpenKeychain/src/main/res/raw-it/help_changelog.md
index 2cc690901..21b05c8d2 100644
--- a/OpenKeychain/src/main/res/raw-it/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-it/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTA: Si prega di mettere ogni frase in una propria linea, Transifex mette ogni riga nel proprio campo di traduzione!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-ja/help_changelog.md b/OpenKeychain/src/main/res/raw-ja/help_changelog.md
index c5ab2b2c1..9c6dc7208 100644
--- a/OpenKeychain/src/main/res/raw-ja/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-ja/help_changelog.md
@@ -1,11 +1,16 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
- * New decryption screen
- * Decryption of multiple files at once
- * Better handling of YubiKey errors
+ * 新しい復号画面
+ * 一度に複数のファイルの復号
+ * YubiKeyのエラーについてよりよい扱い
## 3.2
diff --git a/OpenKeychain/src/main/res/raw-kn/help_changelog.md b/OpenKeychain/src/main/res/raw-kn/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-kn/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-kn/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-nl/help_about.md b/OpenKeychain/src/main/res/raw-nl/help_about.md
index 6f64c0fd8..e5206fd84 100644
--- a/OpenKeychain/src/main/res/raw-nl/help_about.md
+++ b/OpenKeychain/src/main/res/raw-nl/help_about.md
@@ -57,7 +57,7 @@ Licentie: GPLv3+
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache licentie v2)
* [ZXing](https://github.com/zxing/zxing) (Apache licentie v2)
* [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Apache licentie v2)
- * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
+ * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache licentie v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache licentie v2)
* [Snackbar](https://github.com/nispok/snackbar) (MIT licentie)
* [FloatingActionButton](https://github.com/futuresimple/android-floating-action-button) (Apache licentie v2)
diff --git a/OpenKeychain/src/main/res/raw-nl/help_changelog.md b/OpenKeychain/src/main/res/raw-nl/help_changelog.md
index 577ff26b0..88b23916b 100644
--- a/OpenKeychain/src/main/res/raw-nl/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-nl/help_changelog.md
@@ -1,11 +1,16 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
- * New decryption screen
- * Decryption of multiple files at once
- * Better handling of YubiKey errors
+ * Nieuw ontsleutelingsscherm
+ * Ontsleuteling van meerdere bestanden tegelijk
+ * Beter verwerken van YubiKey-fouten
## 3.2
diff --git a/OpenKeychain/src/main/res/raw-pl/help_about.md b/OpenKeychain/src/main/res/raw-pl/help_about.md
index e80a2c766..eb3328cfa 100644
--- a/OpenKeychain/src/main/res/raw-pl/help_about.md
+++ b/OpenKeychain/src/main/res/raw-pl/help_about.md
@@ -2,12 +2,12 @@
[http://www.openkeychain.org](http://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) is an OpenPGP implementation for Android.
+[OpenKeychain](http://www.openkeychain.org) jest implementacją OpenPGP dla Androida.
-License: GPLv3+
+Licencja: GPLv3+
-## Main Developers
- * Dominik Schürmann (Maintainer)
+## Główni deweloperzy
+ * Dominik Schürmann (Opiekun projektu)
* Vincent Breitmoser
## Contributors
@@ -47,7 +47,7 @@ License: GPLv3+
* 'Thialfihar' (APG developer)
* Tim Bray
-## Libraries
+## Biblioteki
* [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Android Support Libraries](http://developer.android.com/tools/support-library/index.html) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-pl/help_certification.md b/OpenKeychain/src/main/res/raw-pl/help_certification.md
index 3518adf73..8031f7a87 100644
--- a/OpenKeychain/src/main/res/raw-pl/help_certification.md
+++ b/OpenKeychain/src/main/res/raw-pl/help_certification.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-## Key Confirmation
-Without confirmation, you cannot be sure if a key really corresponds to a specific person.
-The simplest way to confirm a key is by scanning the QR Code or exchanging it via NFC.
+## Potwiedzenie klucza
+Bez potwierdzenia nie masz pewności czy klucz odpowiada danej osobie.
+Najłatwiejszą drogą potwierdzenia klucza jest zeskanowanie kodu QR lub wysłanie go przez NFC
To confirm keys between more than two persons, we suggest to use the key exchange method available for your keys.
## Key Status
diff --git a/OpenKeychain/src/main/res/raw-pl/help_changelog.md b/OpenKeychain/src/main/res/raw-pl/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-pl/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-pl/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-pt/help_changelog.md b/OpenKeychain/src/main/res/raw-pt/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-pt/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-pt/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-ro/help_changelog.md b/OpenKeychain/src/main/res/raw-ro/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-ro/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-ro/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-ru/help_changelog.md b/OpenKeychain/src/main/res/raw-ru/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-ru/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-ru/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-sl/help_changelog.md b/OpenKeychain/src/main/res/raw-sl/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-sl/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-sl/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-sr/help_about.md b/OpenKeychain/src/main/res/raw-sr/help_about.md
index a6ba4ba2c..d4b6ba700 100644
--- a/OpenKeychain/src/main/res/raw-sr/help_about.md
+++ b/OpenKeychain/src/main/res/raw-sr/help_about.md
@@ -57,7 +57,7 @@
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Апачи лиценца в2)
* [ZXing](https://github.com/zxing/zxing) (Апачи лиценца в2)
* [ZXing Android Minimal](https://github.com/journeyapps/zxing-android-embedded) (Апачи лиценца в2)
- * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
+ * [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Материјал дизајн) (Апачи лиценца в2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Апачи лиценца в2)
* [Snackbar](https://github.com/nispok/snackbar) (МИТ лиценца)
* [FloatingActionButton](https://github.com/futuresimple/android-floating-action-button) (Апачи лиценца в2)
diff --git a/OpenKeychain/src/main/res/raw-sr/help_changelog.md b/OpenKeychain/src/main/res/raw-sr/help_changelog.md
index bb230ab96..3fe45259b 100644
--- a/OpenKeychain/src/main/res/raw-sr/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-sr/help_changelog.md
@@ -1,11 +1,16 @@
[//]: #
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
- * New decryption screen
- * Decryption of multiple files at once
- * Better handling of YubiKey errors
+ * Нови екран дешифровања
+ * Дешифровање више фајлова одједном
+ * Боље руковање грешкама Јубикључа
## 3.2
@@ -21,7 +26,7 @@
* Поправка: неки од важећих кључева су били приказивани као опозвани или истекли
* Не прихатај потписе од истеклих или опозваних кључева
* Keybase.io подршка у напредном приказу
- * метода ажурирања свих кључева одједном
+ * Метода ажурирања свих кључева одједном
## 3.1.2
diff --git a/OpenKeychain/src/main/res/raw-sv/help_changelog.md b/OpenKeychain/src/main/res/raw-sv/help_changelog.md
index b80e08e6e..83e4a8e06 100644
--- a/OpenKeychain/src/main/res/raw-sv/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-sv/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTERING: Var vänlig och sätt varje mening på sin egen rad, Transifex sätter varje rad i sitt eget fält för översättningar!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-tr/help_changelog.md b/OpenKeychain/src/main/res/raw-tr/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-tr/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-tr/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-uk/help_changelog.md b/OpenKeychain/src/main/res/raw-uk/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-uk/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-uk/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-vi/help_changelog.md b/OpenKeychain/src/main/res/raw-vi/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-vi/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-vi/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md b/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md
index da95f2184..ad9be42be 100644
--- a/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw-zh/help_changelog.md b/OpenKeychain/src/main/res/raw-zh/help_changelog.md
index d45ce636b..45ac104e0 100644
--- a/OpenKeychain/src/main/res/raw-zh/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-zh/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/raw/help_changelog.md b/OpenKeychain/src/main/res/raw/help_changelog.md
index 1c9d27629..df61f3472 100644
--- a/OpenKeychain/src/main/res/raw/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw/help_changelog.md
@@ -1,5 +1,10 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.4
+
+ * Anonymous key download over Tor
+ * Proxy support
+ * Better YubiKey error handling
## 3.3
diff --git a/OpenKeychain/src/main/res/values-ar/strings.xml b/OpenKeychain/src/main/res/values-ar/strings.xml
index 8f84af665..0713e39ad 100644
--- a/OpenKeychain/src/main/res/values-ar/strings.xml
+++ b/OpenKeychain/src/main/res/values-ar/strings.xml
@@ -7,6 +7,11 @@
<!--button-->
<!--menu-->
<!--label-->
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<!--choice-->
<!--key flags-->
<!--sentences-->
@@ -42,7 +47,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -61,6 +66,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-bg/strings.xml b/OpenKeychain/src/main/res/values-bg/strings.xml
index 8f84af665..0713e39ad 100644
--- a/OpenKeychain/src/main/res/values-bg/strings.xml
+++ b/OpenKeychain/src/main/res/values-bg/strings.xml
@@ -7,6 +7,11 @@
<!--button-->
<!--menu-->
<!--label-->
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<!--choice-->
<!--key flags-->
<!--sentences-->
@@ -42,7 +47,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -61,6 +66,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-cs/strings.xml b/OpenKeychain/src/main/res/values-cs/strings.xml
index 545778ff7..4b367a5b3 100644
--- a/OpenKeychain/src/main/res/values-cs/strings.xml
+++ b/OpenKeychain/src/main/res/values-cs/strings.xml
@@ -111,7 +111,6 @@
<string name="label_use_default_yubikey_pin">Použít výchozí YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Použít numerickou klávesnici pro YubiKey PIN</string>
<string name="label_label_use_default_yubikey_pin_summary">Používá základní PIN (123456) pro přístup k YubiKey přes NFC</string>
- <string name="label_asymmetric_from">Podepsáno:</string>
<string name="label_to">Zašifrovat pro:</string>
<string name="label_delete_after_encryption">Smazat soubory po zašifrování</string>
<string name="label_delete_after_decryption">Smazat po rozšifrování</string>
@@ -135,7 +134,6 @@
<string name="label_send_key">Synchronizovat s cloudem</string>
<string name="label_fingerprint">Otisk</string>
<string name="expiry_date_dialog_title">Nastavit datum expirace</string>
- <string name="label_first_keyserver_is_used">(Výchozí je první keyserver)</string>
<string name="label_preferred">upřednostněno</string>
<string name="label_enable_compression">Zapnout kompresi</string>
<string name="label_encrypt_filenames">Zašifrovat jména souborů</string>
@@ -146,6 +144,11 @@
<string name="pref_keyserver_summary">Vyhledat klíče na vybraném OpenPGP keyserveru (protokol HKP)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Hledat klíče na keybase.io</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;beze jména&gt;</string>
<string name="none">&lt;žádný&gt;</string>
<plurals name="n_keys">
@@ -195,7 +198,6 @@
<string name="passphrase_for">Zadejte heslo pro \'%s\'</string>
<string name="pin_for">Zadejte PIN pro \'%s\'</string>
<string name="yubikey_pin_for">Zadejte PIN pro přístup k YubiKey pro \'%s\'</string>
- <string name="nfc_text">Přidržte YubiKey u zadní strany vašeho přístroje.</string>
<string name="file_delete_confirmation_title">Smazat původní soubory?</string>
<string name="file_delete_confirmation">Následjící soubory budou vymazány:%s</string>
<string name="file_delete_successful">%1$d z %2$d souborů bylo vymazáno.%3$s</string>
@@ -204,7 +206,7 @@
<string name="select_encryption_key">Vyberte alespoň jeden šifrovací klíč.</string>
<string name="specify_file_to_encrypt_to">Prosím specifikujte do kterého souboru zašifrovat.\nVAROVÁNÍ: Pokud soubor již existuje, bude přepsán.</string>
<string name="specify_file_to_decrypt_to">Prosím specifikujte do kterého souboru rozšifrovat.\nVAROVÁNÍ: Pokud soubor již existuje, bude přepsán.</string>
- <string name="specify_file_to_export_to">Prosím specifikujte do kterého souboru exportovat.\nVAROVÁNÍ: Pokud soubor již existuje, bude přepsán.</string>
+ <string name="specify_backup_dest">Prosím specifikujte do kterého souboru exportovat.\nVAROVÁNÍ: Pokud soubor již existuje, bude přepsán.</string>
<string name="key_deletion_confirmation_multi">Opravdu chcete smazat všechny vybrané soubory?</string>
<string name="secret_key_deletion_confirmation">Po smazání již nebudete schopni přečíst zprávy zašifrované tímto klíčem a stratíte všechny potvrzení udělané tímto klíčem!</string>
<string name="public_key_deletetion_confirmation">Smazat klíč \'%s\'?</string>
@@ -387,7 +389,7 @@
<string name="api_settings_start">Spustit aplikaci</string>
<string name="api_settings_delete_account">Smazat účet</string>
<string name="api_settings_package_name">Jméno balíčku</string>
- <string name="api_settings_package_signature">SHA-256 z podpisu balíčku</string>
+ <string name="api_settings_package_certificate">SHA-256 z podpisu balíčku</string>
<string name="api_settings_settings">Nastavení</string>
<string name="api_settings_key">Klíč účtu:</string>
<string name="api_settings_accounts_empty">Žádné účty nejsou specifikovány pro tuto appku.</string>
@@ -502,7 +504,7 @@
<string name="view_key_verified">Potvrzený klíč</string>
<string name="view_key_unverified">Nepotvrzen: Naskenujte QR kód abyste ho potvrdili!</string>
<string name="view_key_fragment_no_system_contact">&lt;žádný&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Přidat keyserver</string>
<string name="add_keyserver_verified">Keyserver ověřen!</string>
<string name="add_keyserver_without_verification">Keyserver přidán bez verifikace.</string>
@@ -656,6 +658,7 @@
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_acc_saved">Účet uložen</string>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml
index b5990a82e..fe9963a91 100644
--- a/OpenKeychain/src/main/res/values-de/strings.xml
+++ b/OpenKeychain/src/main/res/values-de/strings.xml
@@ -48,12 +48,16 @@
<string name="section_key_server">Schlüsselserver</string>
<string name="section_fingerprint">Fingerabdruck</string>
<string name="section_encrypt">Verschlüsseln</string>
+ <string name="section_decrypt">Entschlüsseln / Verifizieren</string>
<string name="section_current_expiry">Aktuelles Ablaufdatum</string>
<string name="section_new_expiry">Neues Ablaufdatum</string>
<!--button-->
<string name="btn_decrypt_verify_file">Datei entschlüsseln, verifizieren und speichern</string>
<string name="btn_encrypt_share_file">Datei verschlüsseln und teilen</string>
<string name="btn_encrypt_save_file">Datei verschlüsseln und speichern</string>
+ <string name="btn_save_file">Datei speichern</string>
+ <string name="btn_save">Speichern</string>
+ <string name="btn_view_log">Log ansehen</string>
<string name="btn_do_not_save">Abbrechen</string>
<string name="btn_delete">Löschen</string>
<string name="btn_no_date">Kein Ablaufdatum</string>
@@ -70,6 +74,8 @@
<string name="btn_add_files">Datei(en) hinzufügen</string>
<string name="btn_share_decrypted_text">Entschlüsselten Text teilen</string>
<string name="btn_copy_decrypted_text">Entschlüsselten Text kopieren</string>
+ <string name="btn_decrypt_clipboard">Aus Zwischenablage lesen</string>
+ <string name="btn_decrypt_files">Input Datei auswählen.</string>
<string name="btn_encrypt_files">Dateien verschlüsseln</string>
<string name="btn_encrypt_text">Text verschlüsseln</string>
<string name="btn_add_email">Weitere E-Mail-Adresse hinzufügen</string>
@@ -111,7 +117,6 @@
<string name="label_use_default_yubikey_pin">Standard-YubiKey-PIN verwenden</string>
<string name="label_use_num_keypad_for_yubikey_pin">Zifferntastatur für YubiKey PIN verwenden</string>
<string name="label_label_use_default_yubikey_pin_summary">Verwendet zum Zugriff auf YubiKeys über NFC die Standard-PIN (123456)</string>
- <string name="label_asymmetric_from">Signiert von:</string>
<string name="label_to">Verschlüsselt an:</string>
<string name="label_delete_after_encryption">Dateien nach Verschlüsselung löschen</string>
<string name="label_delete_after_decryption">Nach Entschlüsselung löschen</string>
@@ -135,7 +140,6 @@
<string name="label_send_key">Mit der Cloud synchronisieren</string>
<string name="label_fingerprint">Fingerabdruck</string>
<string name="expiry_date_dialog_title">Ablaufdatum festsetzen</string>
- <string name="label_first_keyserver_is_used">(Oberster Schlüsselserver wird bevorzugt)</string>
<string name="label_preferred">bevorzugt</string>
<string name="label_enable_compression">Komprimierung aktivieren</string>
<string name="label_encrypt_filenames">Dateinamen verschlüsseln</string>
@@ -146,6 +150,11 @@
<string name="pref_keyserver_summary">Schlüssel auf ausgewählten OpenPGP-Schlüsselservern suchen (HKP-Protokoll)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Schlüssel auf keybase.io suchen</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;kein Name&gt;</string>
<string name="none">&lt;keine&gt;</string>
<plurals name="n_keys">
@@ -193,16 +202,16 @@
<string name="passphrase_for">Passwort für \'%s\' eingeben</string>
<string name="pin_for">PIN für \'%s\' eingeben</string>
<string name="yubikey_pin_for">PIN für Zugriff auf Yubikey für \'%s\' eingeben</string>
- <string name="nfc_text">Halte YubiKey gegen die Rückseite Deines Geräts.</string>
<string name="file_delete_confirmation_title">Originaldateien löschen?</string>
<string name="file_delete_confirmation">Die folgenden Dateien werden gelöscht: %s</string>
<string name="file_delete_successful">%1$d von %2$d Dateien wurden gelöscht.%3$s</string>
+ <string name="no_file_selected">Keine Datei ausgewählt.</string>
<string name="encrypt_sign_successful">Erfolgreich signiert und/oder verschlüsselt.</string>
<string name="encrypt_sign_clipboard_successful">Erfolgreich in die Zwischenablage signiert und/oder verschlüsselt.</string>
<string name="select_encryption_key">Mindestens einen Schlüssel zum Verschlüsseln auswählen.</string>
<string name="specify_file_to_encrypt_to">Bitte angeben in welche Datei verschlüsselt werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert.</string>
<string name="specify_file_to_decrypt_to">Bitte angeben in welche Datei entschlüsselt werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert.</string>
- <string name="specify_file_to_export_to">Bitte angeben in welche Datei exportiert werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert.</string>
+ <string name="specify_backup_dest">Bitte angeben in welche Datei exportiert werden soll.\nWARNUNG: Datei wird überschrieben, wenn sie bereits existiert.</string>
<string name="key_deletion_confirmation_multi">Möchtest du wirklich alle ausgewählten Schlüssel löschen?</string>
<string name="secret_key_deletion_confirmation">Nach dem Löschen wird es dir nicht mehr möglich sein mit diesem Schlüssel verschlüsselte Nachrichten zu lesen und zudem wirst du alle damit getätigten Bestätigungen verlieren!</string>
<string name="public_key_deletetion_confirmation">Schlüssel \'%s\' löschen?</string>
@@ -368,6 +377,7 @@
<!--Import from URL-->
<string name="import_url_warn_no_search_parameter">Kein Suchbegriff angegeben. Sie können trotzdem manuell auf dem Keyserver suchen.</string>
<!--Generic result toast-->
+ <string name="snackbar_details">Details</string>
<string name="with_warnings">, mit Warnungen</string>
<string name="with_cancelled">. bis abgebrochen wurde</string>
<!--Import result toast-->
@@ -449,7 +459,7 @@
<string name="api_settings_start">Starte Anwendung</string>
<string name="api_settings_delete_account">Benutzerkonto löschen</string>
<string name="api_settings_package_name">Paketname</string>
- <string name="api_settings_package_signature">SHA-256 der Paketsignatur</string>
+ <string name="api_settings_package_certificate">SHA-256 der Paketsignatur</string>
<string name="api_settings_accounts">Benutzerkonten (veraltete API)</string>
<string name="api_settings_advanced">Erweiterte Informationen</string>
<string name="api_settings_allowed_keys">Erlaubte Schlüssel</string>
@@ -594,7 +604,7 @@
<string name="view_key_verified">Bestätigter Schlüssel</string>
<string name="view_key_unverified">Unbestätigt: QR-Code scannen, um den Schlüssel zu bestätigen!</string>
<string name="view_key_fragment_no_system_contact">&lt;keine&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Schlüsselserver hinzufügen</string>
<string name="add_keyserver_verified">Schlüsselserver bestätigt!</string>
<string name="add_keyserver_without_verification">Schlüsselserver ohne Überprüfung hinzugefügt.</string>
@@ -954,7 +964,6 @@
<string name="msg_dc_error_integrity_check">Integritätsprüfungsfehler!</string>
<string name="msg_dc_error_integrity_missing">Fehlende Integritätsprüfung Dies kann passieren, wenn die Verschlüsselungsanwendung veraltet ist oder durch einen Downgrade-Angriff.</string>
<string name="msg_dc_error_invalid_data">Kein gültiger OpenPGP-verschlüsselter oder -signierter Inhalt!</string>
- <string name="msg_dc_error_io">Ein-/Ausgabefehler während Vorgang aufgetreten!</string>
<string name="msg_dc_error_no_data">Keine verschlüsselten Daten in Datenstrom gefunden!</string>
<string name="msg_dc_error_no_key">Keine verschlüsselten Daten mit bekanntem geheimen Schlüssel in Datenstrom gefunden!</string>
<string name="msg_dc_error_pgp_exception">Es ist ein OpenPGP-Ausnahmefehler während des Vorgangs aufgetreten!</string>
@@ -1109,6 +1118,10 @@
<string name="msg_download_too_many_responses">Schlüsselsuchanfrage lieferte zu viele Kandidaten, bitte die Suchanfrage verfeinern!</string>
<string name="msg_download_query_too_short_or_too_many_responses">Entweder keine oder zu viele Schlüssel wurden gefunden, bitte die Suchanfrage prä­zi­sie­ren!</string>
<string name="msg_download_query_failed">Beim Suchen der Schlüssel ist ein Fehler aufgetreten.</string>
+ <!--Messages for Keybase Verification operation-->
+ <string name="msg_keybase_error_no_prover">Kein Nachweis-Prüfer gefunden für %s</string>
+ <string name="msg_keybase_error_fetching_evidence">Problem beim Holen des Nachweises</string>
+ <string name="msg_keybase_error_key_mismatch">Schlüssel-Fingerabdruck stimmt nicht mit dem Fingerabdruck im Nachweis überein</string>
<!--Messages for Export Log operation-->
<string name="msg_export_log_start">Exportiere Protokoll</string>
<string name="msg_export_log_error_fopen">Fehler beim Öffnen der Datei</string>
@@ -1123,6 +1136,7 @@
<string name="first_time_import_key">Schlüssel aus Datei importieren</string>
<string name="first_time_yubikey">YubiKey NEO verwenden</string>
<string name="first_time_skip">Setup überspringen</string>
+ <string name="first_time_blank_yubikey_yes">Diesen YubiKey verwenden</string>
<!--unsorted-->
<string name="section_certifier_id">Beglaubiger</string>
<string name="section_cert">Beglaubigungsdetails</string>
@@ -1147,7 +1161,7 @@
<string name="unknown_algorithm">unbekannt</string>
<string name="can_sign_not">Kann nicht unterschreiben</string>
<string name="error_no_encrypt_subkey">Kein Unterschlüssel zum Verschlüsseln verfügbar!</string>
- <string name="info_no_manual_account_creation">Erstelle OpenKeychain-Benutzerkonten nicht manuell.\nFür mehr Informationen sieh in die Hilfe.</string>
+ <string name="account_no_manual_account_creation">Erstelle OpenKeychain-Benutzerkonten nicht manuell.\nFür mehr Informationen sieh in die Hilfe.</string>
<string name="contact_show_key">Schlüssel anzeigen (%s)</string>
<string name="swipe_to_update">Nach unten wischen um von Schlüsselserver zu aktualisieren</string>
<string name="error_no_file_selected">Mindestens eine Datei zum Verschlüsseln auswählen!</string>
@@ -1195,15 +1209,9 @@
<string name="btn_import">Import</string>
<string name="snack_yubi_other">Anderer Schlüssel auf YubiKey gespeichert!</string>
<string name="error_nfc">NFC-Fehler: %s</string>
- <string name="error_pin">NFC: Falsche PIN, %d Versuche verbleibend</string>
- <string name="error_nfc_wrong_length">NFC: Falsche Länge für gesendete/empfangene Daten</string>
- <string name="error_nfc_security_not_satisfied">NFC: Sicherheitsstatus nicht zufriedenstellend</string>
- <string name="error_nfc_authentication_blocked">NFC: PIN nach zu vielen Versuchen gesperrt</string>
- <string name="error_nfc_data_not_found">NFC: Schlüssel oder Objekt nicht gefunden</string>
- <string name="error_nfc_unknown">NFC: Unbekannter Fehler</string>
- <string name="error_nfc_bad_data">NFC: Karte meldete ungültige Daten</string>
- <string name="error_nfc_header">NFC: Karte meldete ungültige %s Byte</string>
<string name="error_pin_nodefault">Standard-PIN abgelehnt</string>
+ <string name="error_temp_file">Erstellen der temporären Datei fehlgeschlagen.</string>
+ <string name="btn_delete_original">Original Datei löschen</string>
<string name="snack_encrypt_filenames_on">Dateinamen <b>sind</b> verschlüsselt.</string>
<string name="snack_encrypt_filenames_off">Dateinamen <b>sind nicht</b> verschlüsselt.</string>
<string name="snack_armor_on">Ausgabe als Text kodiert.</string>
@@ -1212,4 +1220,14 @@
<string name="snack_compression_off">Komprimierung <b>deaktiviert</b>.</string>
<string name="error_loading_keys">Fehler beim Laden der Schlüssel!</string>
<string name="error_empty_log">(Fehler, leeres Protokoll)</string>
+ <string name="view_internal">In OpenKeychain ansehen</string>
+ <string name="error_preparing_data">Fehler beim Vorbereiten der Daten!</string>
+ <string name="label_clip_title">Verschlüsselte Daten</string>
+ <string name="progress_processing">Verarbeiten...</string>
+ <string name="error_saving_file">Fehler beim Speichern der Datei!</string>
+ <string name="file_saved">Datei gespeichert!</string>
+ <string name="file_delete_ok">Original Datei gelöscht</string>
+ <string name="file_delete_none">Keine Datei gelöscht! (bereits gelöscht?)</string>
+ <string name="file_delete_exception">Original Datei konnte nicht gelöscht werden!</string>
+ <string name="error_clipboard_empty">Zwischenablage ist leer!</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index f120f411d..2287ac121 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -43,6 +43,7 @@
<string name="section_keys">Subclaves</string>
<string name="section_cloud_search">Búsqueda en la nube</string>
<string name="section_passphrase_cache">Manejo de contraseña/PIN</string>
+ <string name="section_proxy_settings">Configuración para proxy</string>
<string name="section_certify">Confirmar</string>
<string name="section_actions">Acciones</string>
<string name="section_share_key">Clave</string>
@@ -56,6 +57,8 @@
<string name="btn_decrypt_verify_file">Desencriptar, verificar, y guardar fichero</string>
<string name="btn_encrypt_share_file">Encriptar y compartir fichero</string>
<string name="btn_encrypt_save_file">Encriptar y guardar fichero</string>
+ <string name="btn_save_file">Guardar fichero</string>
+ <string name="btn_save">Guardar</string>
<string name="btn_view_log">Ver registro (log)</string>
<string name="btn_do_not_save">Cancelar</string>
<string name="btn_delete">Eliminar</string>
@@ -98,6 +101,7 @@
<string name="menu_advanced">Información extendida</string>
<string name="menu_certify_fingerprint">Confirmar mediante comparación de la huella digital</string>
<string name="menu_export_log">Exportar registro</string>
+ <string name="menu_keyserver_add">Añadir</string>
<!--label-->
<string name="label_message">Texto</string>
<string name="label_file">Archivo</string>
@@ -116,7 +120,6 @@
<string name="label_use_default_yubikey_pin">Utilizar PIN predeterminado de la YubiKey</string>
<string name="label_use_num_keypad_for_yubikey_pin">Utilizar teclado numérico para el PIN de la YubiKey</string>
<string name="label_label_use_default_yubikey_pin_summary">Utiliza el PIN predeterminado (123456) para acceder a las YubiKeys sobre NFC</string>
- <string name="label_asymmetric_from">Firmado por:</string>
<string name="label_to">Cifrar hacia:</string>
<string name="label_delete_after_encryption">Borrar ficheros después del cifrado</string>
<string name="label_delete_after_decryption">Eliminar fichero después del descifrado</string>
@@ -142,17 +145,49 @@
<string name="label_send_key">Sincronizar con la nube</string>
<string name="label_fingerprint">Huella digital</string>
<string name="expiry_date_dialog_title">Establer la fecha de vencimiento</string>
- <string name="label_first_keyserver_is_used">(Se prefiere el primer servidor de claves listado)</string>
+ <string name="label_keyservers_title">Servidores de claves</string>
+ <string name="label_keyserver_settings_hint">Arrastrar para cambiar orden, pulsar para editar/borrar</string>
+ <string name="label_selected_keyserver_title">Servidor de claves seleccionado</string>
<string name="label_preferred">preferido</string>
<string name="label_enable_compression">Habilitar compresión</string>
<string name="label_encrypt_filenames">Cifrar nombres de ficheros</string>
<string name="label_hidden_recipients">Ocultar receptores</string>
<string name="label_verify_keyserver">Verificar servidor de claves</string>
<string name="label_enter_keyserver_url">Introduzca URL de servidor de claves</string>
+ <string name="label_keyserver_dialog_delete">Borrar servidor de claves</string>
<string name="pref_keyserver">Servidores de claves OpenPGP</string>
<string name="pref_keyserver_summary">Busca claves en los servidores de claves OpenPGP seleccionados (protocolo HKP)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Busca claves en keybase.io</string>
+ <!--Proxy Preferences-->
+ <string name="pref_proxy_tor_title">Habilitar Tor</string>
+ <string name="pref_proxy_tor_summary">Requiere que Orbot esté instalado</string>
+ <string name="pref_proxy_normal_title">Habilitar otro proxy</string>
+ <string name="pref_proxy_host_title">Servidor proxy</string>
+ <string name="pref_proxy_host_err_invalid">El servidor proxy (interpuesto) no puede estar vacío</string>
+ <string name="pref_proxy_port_title">Puerto de proxy</string>
+ <string name="pref_proxy_port_err_invalid">Número de puerto introducido no válido</string>
+ <string name="pref_proxy_type_title">Tipo de proxy</string>
+ <!--proxy type choices and values-->
+ <string name="pref_proxy_type_choice_http">HTTP</string>
+ <string name="pref_proxy_type_choice_socks">SOCKS</string>
+ <string name="pref_proxy_type_value_http">proxyHttp</string>
+ <string name="pref_proxy_type_value_socks">proxySocks</string>
+ <!--OrbotHelper strings-->
+ <string name="orbot_ignore_tor">No usar Tor</string>
+ <!--InstallDialogFragment strings-->
+ <string name="orbot_install_dialog_title">¿Instalar Orbot para usar Tor?</string>
+ <string name="orbot_install_dialog_install">Instalar</string>
+ <string name="orbot_install_dialog_content">Tiene que tener Orbot instalado y activado para proxyficar el tráfico a través de él. ¿Desea instalarlo?</string>
+ <string name="orbot_install_dialog_cancel">Cancelar</string>
+ <string name="orbot_install_dialog_ignore_tor">No usar Tor</string>
+ <!--StartOrbotDialogFragment strings-->
+ <string name="orbot_start_dialog_title">¿Iniciar Orbot?</string>
+ <string name="orbot_start_dialog_content">Orbot no parece estar corriendo. ¿Desea iniciarlo y conectar a Tor?</string>
+ <string name="orbot_start_btn">Iniciar Orbot</string>
+ <string name="orbot_start_dialog_start">Iniciar Orbot</string>
+ <string name="orbot_start_dialog_cancel">Cancelar</string>
+ <string name="orbot_start_dialog_ignore_tor">No usar Tor</string>
<string name="user_id_no_name">&lt;sin nombre&gt;</string>
<string name="none">&lt;ninguna&gt;</string>
<plurals name="n_keys">
@@ -200,7 +235,8 @@
<string name="passphrase_for">Introduzca contraseña para \'%s\'</string>
<string name="pin_for">Introduzca el PIN para \'%s\'</string>
<string name="yubikey_pin_for">Introduzca el PIN para acceder a la YubiKey para \'%s\'</string>
- <string name="nfc_text">Sostenga la YubiKey contra el reverso de su dispositivo.</string>
+ <string name="nfc_text">Sostenga la YubiKey contra el marcador NFC en el reverso de su dispositivo.</string>
+ <string name="nfc_wait">¡Mantenga la YubiKey en el reverso!</string>
<string name="file_delete_confirmation_title">¿Borrar ficheros originales?</string>
<string name="file_delete_confirmation">Los siguientes ficheros se borrarán:%s</string>
<string name="file_delete_successful">%1$d de %2$d ficheros han sido borrados.%3$s</string>
@@ -211,7 +247,7 @@
<string name="error_no_encryption_or_signature_key">Seleccionar al menos una clave de cifrado o una clave de firma.</string>
<string name="specify_file_to_encrypt_to">Por favor especifique hacia qué fichero cifrar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
<string name="specify_file_to_decrypt_to">Por favor especifique hacia qué fichero descifrar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
- <string name="specify_file_to_export_to">Por favor especifique hacia qué fichero exportar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
+ <string name="specify_backup_dest">Por favor especifique hacia qué fichero exportar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
<string name="key_deletion_confirmation_multi">¿De verdad quiere borrar todas las claves seleccionadas?</string>
<string name="secret_key_deletion_confirmation">¡Después del borrado no podrá leer mensajes cifrados con esta clave y perderá todas las confirmaciones de clave hechas con ella!</string>
<string name="public_key_deletetion_confirmation">¿Borrar clave \'%s\'?</string>
@@ -304,6 +340,8 @@
<string name="progress_modify_subkeystrip">desnudando claves...</string>
<string name="progress_modify_subkeyadd">añadiendo subclaves...</string>
<string name="progress_modify_passphrase">cambiando contraseña...</string>
+ <string name="progress_modify_pin">cambiando PIN...</string>
+ <string name="progress_modify_admin_pin">cambiando el PIN de Admin...</string>
<plurals name="progress_exporting_key">
<item quantity="one">exportando clave...</item>
<item quantity="other">exportando claves...</item>
@@ -459,7 +497,7 @@
<string name="api_settings_start">Iniciar aplicación</string>
<string name="api_settings_delete_account">Borrar cuenta</string>
<string name="api_settings_package_name">Nombre de paquete</string>
- <string name="api_settings_package_signature">SHA-256 de firma de paquete</string>
+ <string name="api_settings_package_certificate">SHA-256 de firma de paquete</string>
<string name="api_settings_accounts">Cuentas (API antigua)</string>
<string name="api_settings_advanced">Información extendida</string>
<string name="api_settings_allowed_keys">Claves permitidas</string>
@@ -596,6 +634,13 @@
<string name="create_key_add_email_text">Las direcciones adicionales de correo electrónico también están asociadas a esta clave y pueden utilizarse para asegurar la comunicación.</string>
<string name="create_key_email_already_exists_text">Esta dirección de correo electrónico ya fue añadida</string>
<string name="create_key_email_invalid_email">El formato de la dirección de correo no es válido</string>
+ <string name="create_key_yubi_key_pin_text">Por favor, recuerde el PIN, se requiere para usar su YubiKey más tarde. Por favor, escriba el PIN de Admin y guárdelo en un lugar seguro.</string>
+ <string name="create_key_yubi_key_pin">PIN</string>
+ <string name="create_key_yubi_key_admin_pin">PIN de Admin</string>
+ <string name="create_key_yubi_key_pin_repeat_text">Por favor, introduzca el PIN y el PIN de Admin para proceder.</string>
+ <string name="create_key_yubi_key_pin_repeat">Repita el PIN</string>
+ <string name="create_key_yubi_key_admin_pin_repeat">Repita el PIN de Admin</string>
+ <string name="create_key_yubi_key_pin_not_correct">¡El PIN no es correcto!</string>
<!--View key-->
<string name="view_key_revoked">Revocada: ¡La clave no debe volver a ser usada!</string>
<string name="view_key_expired">Caducada: ¡El contacto necesita extender la vigencia de la clave!</string>
@@ -604,12 +649,15 @@
<string name="view_key_verified">Clave confirmada</string>
<string name="view_key_unverified">No confirmada: ¡Escanee el código QR para confirmar clave!</string>
<string name="view_key_fragment_no_system_contact">&lt;ninguno&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Añadir servidor de claves</string>
+ <string name="edit_keyserver_dialog_title">Editar servidor de claves</string>
<string name="add_keyserver_verified">¡Servidor de claves verificado!</string>
<string name="add_keyserver_without_verification">Servidor de claves añadido sin verificación</string>
<string name="add_keyserver_invalid_url">¡URL no válida!</string>
<string name="add_keyserver_connection_failed">Fallo al conectar al servidor de claves. Por favor, compuebe la URL y su conexión a Internet.</string>
+ <string name="keyserver_preference_deleted">%s borrado</string>
+ <string name="keyserver_preference_cannot_delete_last">No se puede borrar el último servidor de claves. ¡Se requiere al menos uno!</string>
<!--Navigation Drawer-->
<string name="nav_keys">Claves</string>
<string name="nav_encrypt_decrypt">Cifrar/Descifrar</string>
@@ -868,6 +916,8 @@
<string name="msg_mf_notation_empty">Añadiendo paquete de notación vacío</string>
<string name="msg_mf_notation_pin">Añadiendo paquete de notación de PIN</string>
<string name="msg_mf_passphrase">Cambiando contraseña para el juego de claves</string>
+ <string name="msg_mf_pin">Cambiando el PIN en la tarjeta</string>
+ <string name="msg_mf_admin_pin">Cambiando el PIN de Admin en la tarjeta</string>
<string name="msg_mf_passphrase_key">Re-cifrando subclave %s con la nueva contraseña</string>
<string name="msg_mf_passphrase_empty_retry">El establecimiento de la nueva contraseña falló, volviéndolo a intentar con una contraseña antigua vacía.</string>
<string name="msg_mf_passphrase_fail">¡La contraseña para la subclave no se pudo cambiar! (¿Tiene una contraseña diferente a la del resto de las claves?)</string>
@@ -968,7 +1018,8 @@
<string name="msg_dc_error_integrity_check">¡Error de comprobación de integridad!</string>
<string name="msg_dc_error_integrity_missing">¡Verificación de integridad ausente! Esto puede ocurrir porque la aplicación de cifrado no está actualizada, o debido a un ataque desactualización.</string>
<string name="msg_dc_error_invalid_data">¡No se encontraron datos firmados o cifrados con OpenPGP válidos!</string>
- <string name="msg_dc_error_io">¡Se encontró Excepción de E/S durante la operación!</string>
+ <string name="msg_dc_error_io">¡Se encontró un error al leer los datos de entrada!</string>
+ <string name="msg_dc_error_input">¡Error al abrir el flujo de datos de entrada!</string>
<string name="msg_dc_error_no_data">¡No se encontraron datos cifrados en el flujo de datos (`stream`)!</string>
<string name="msg_dc_error_no_key">¡No se encontraron datos cifrados con clave secreta (privada) conocida en el flujo de datos (`stream`)!</string>
<string name="msg_dc_error_pgp_exception">¡Se encontró una excepción OpenPGP durante la operación!</string>
@@ -1058,6 +1109,7 @@
<string name="msg_crt_warn_not_found">¡Clave no encontrada!</string>
<string name="msg_crt_warn_cert_failed">¡La generación de certificado falló!</string>
<string name="msg_crt_warn_save_failed">¡La operación de guardado falló!</string>
+ <string name="msg_crt_warn_upload_failed">¡Fallo en la operación de subida!</string>
<string name="msg_crt_upload_success">Clave subida al servidor con éxito</string>
<plurals name="msg_import">
<item quantity="one">Importando clave</item>
@@ -1084,6 +1136,7 @@
</plurals>
<string name="msg_export_all">Exportando todas las claves</string>
<string name="msg_export_public">Exportando clave pública %s</string>
+ <string name="msg_export_upload_public">Subiendo clave pública %s</string>
<string name="msg_export_secret">Exportando clave secreta (privada) %s</string>
<string name="msg_export_error_no_file">¡No se especificó nombre de fichero!</string>
<string name="msg_export_error_fopen">¡Error al abrir el fichero!</string>
@@ -1093,7 +1146,9 @@
<string name="msg_export_error_db">¡Error de base de datos!</string>
<string name="msg_export_error_io">¡Error de entrada/salida!</string>
<string name="msg_export_error_key">¡Error al preprocesar los datos de la clave!</string>
+ <string name="msg_export_error_upload">¡Error al subir clave al servidor! Por favor, compruebe su conexión a Internet</string>
<string name="msg_export_success">Operación de exportado exitosa</string>
+ <string name="msg_export_upload_success">Subida al servidor de claves completada</string>
<string name="msg_del_error_empty">¡No hay nada que borrar!</string>
<string name="msg_del_error_multi_secret">¡Las claves secretas (privadas) sólo se pueden borrar individualmente!</string>
<plurals name="msg_del">
@@ -1123,6 +1178,14 @@
<string name="msg_download_too_many_responses">La solicitud de búsqueda de clave devolvió demasiados candidatos. ¡Por favor refine su petición!</string>
<string name="msg_download_query_too_short_or_too_many_responses">O bien no hay claves o se han encontrado demasiadas. ¡Por favor mejore su petición!</string>
<string name="msg_download_query_failed">Ocurrió un error al buscar claves.</string>
+ <!--Messages for Keybase Verification operation-->
+ <string name="msg_keybase_verification">Intentando la verificación con Keybase para %s</string>
+ <string name="msg_keybase_error_no_prover">No se encontró prueba verificadora para %s</string>
+ <string name="msg_keybase_error_fetching_evidence">Problema al descargar prueba</string>
+ <string name="msg_keybase_error_key_mismatch">La huella de validación (fingerprint) de la clave no coincide con la prueba publicada</string>
+ <string name="msg_keybase_error_dns_fail">Fallo al obtener Registro DNS TXT</string>
+ <string name="msg_keybase_error_specific">%s</string>
+ <string name="msg_keybase_error_msg_payload_mismatch">La prueba descifrada publicada no coincide con el valor esperado</string>
<!--Messages for Export Log operation-->
<string name="msg_export_log_start">Exportando registro (log)</string>
<string name="msg_export_log_error_fopen">Error abriendo fichero</string>
@@ -1144,6 +1207,8 @@
<string name="first_time_import_key">Importar clave desde fichero</string>
<string name="first_time_yubikey">Usar Yubikey NEO</string>
<string name="first_time_skip">Omitir configuración</string>
+ <string name="first_time_blank_yubikey">¿Desea usar esta YubiKey NEO en blanco con OpenKeychain?\n\n¡Por favor, retire ahora la YubiKey, se le solicitará cuando sea necesaria de nuevo!</string>
+ <string name="first_time_blank_yubikey_yes">Usar esta YubiKey</string>
<!--unsorted-->
<string name="section_certifier_id">Certificador</string>
<string name="section_cert">Detalles del certificado</string>
@@ -1168,7 +1233,7 @@
<string name="unknown_algorithm">desconocido</string>
<string name="can_sign_not">no puede firmarse</string>
<string name="error_no_encrypt_subkey">¡No hay subclave de cifrado disponible!</string>
- <string name="info_no_manual_account_creation">No crear Cuentas-OpenKeychain manualmente.\nPara más información, vea la Ayuda.</string>
+ <string name="account_no_manual_account_creation">No crear Cuentas-OpenKeychain manualmente.\nPara más información, vea la Ayuda.</string>
<string name="contact_show_key">Mostrar clave (%s)</string>
<string name="swipe_to_update">Gesto de barrido hacia abajo para actualizar desde el servidor de claves</string>
<string name="error_no_file_selected">¡Seleccione al menos un fichero a cifrar!</string>
@@ -1219,18 +1284,8 @@
<string name="btn_import">Importar</string>
<string name="snack_yubi_other">¡Clave almacenada en YubiKey distinta!</string>
<string name="error_nfc">Error de NFC: %s</string>
- <string name="error_pin">NFC: PIN incorrecto; %d intentos restantes.</string>
- <string name="error_nfc_terminated">NFC: Tarjeta inteligente caducada</string>
- <string name="error_nfc_wrong_length">NFC: Distancia incorrecta para envío / recepción de datos</string>
- <string name="error_nfc_conditions_not_satisfied">NFC: Condiciones de uso no satisfechas</string>
- <string name="error_nfc_security_not_satisfied">NFC: Estado de seguridad no satisfecho</string>
- <string name="error_nfc_authentication_blocked">NFC: PIN bloqueado tras demasiados intentos</string>
- <string name="error_nfc_data_not_found">NFC: Clave u objeto no encontrado</string>
- <string name="error_nfc_unknown">NFC: Error desconocido</string>
- <string name="error_nfc_bad_data">NFC: La tarjeta informó de datos no válidos</string>
- <string name="error_nfc_chaining_error">NFC: La tarjeta esperaba el último comando en una cadena</string>
- <string name="error_nfc_header">NFC: La tarjeta informó de byte %s no válido</string>
<string name="error_pin_nodefault">¡El PIN por defecto fue rechazado!</string>
+ <string name="error_temp_file">Error al crear fichero temporal.</string>
<string name="btn_delete_original">Borrar fichero original</string>
<string name="snack_encrypt_filenames_on">Los nombres de fichero <b>están</b> cifrados.</string>
<string name="snack_encrypt_filenames_off">Los nombres de fichero <b>no están</b> cifrados.</string>
@@ -1253,4 +1308,6 @@
<string name="file_delete_ok">Fichero original borrado.</string>
<string name="file_delete_none">¡No se borró ningún fichero! (¿ya se había borrado?)</string>
<string name="file_delete_exception">¡No se pudo borrar el fichero original!</string>
+ <string name="error_clipboard_empty">¡Portapapeles vacío!</string>
+ <string name="error_clipboard_copy">¡Error al copiar datos al portapapeles!</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-et/strings.xml b/OpenKeychain/src/main/res/values-et/strings.xml
index 01f98c8e7..8a0481cac 100644
--- a/OpenKeychain/src/main/res/values-et/strings.xml
+++ b/OpenKeychain/src/main/res/values-et/strings.xml
@@ -32,6 +32,11 @@
<string name="label_name">Nimi</string>
<string name="label_comment">Kommentaar</string>
<string name="label_email">E-mail</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="secret_key">Salajane võti:</string>
<!--choice-->
<string name="choice_15secs">15 sekundit</string>
@@ -86,7 +91,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -105,6 +110,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-eu/strings.xml b/OpenKeychain/src/main/res/values-eu/strings.xml
index e58a81911..ca17e0d61 100644
--- a/OpenKeychain/src/main/res/values-eu/strings.xml
+++ b/OpenKeychain/src/main/res/values-eu/strings.xml
@@ -42,18 +42,24 @@
<string name="section_cloud_evidence">Hodeiko probak</string>
<string name="section_keys">Azpigiltzak</string>
<string name="section_cloud_search">Hodei bilaketa</string>
+ <string name="section_passphrase_cache">Sarhitz/PIN Kudeaketa</string>
+ <string name="section_proxy_settings">Proxy Ezarpenak</string>
<string name="section_certify">Baieztatu</string>
<string name="section_actions">Ekintzak</string>
<string name="section_share_key">Giltza</string>
<string name="section_key_server">Giltza-zerbitzaria</string>
<string name="section_fingerprint">Hatz-aztarna</string>
<string name="section_encrypt">Enkriptatu</string>
+ <string name="section_decrypt">Dekriptatu / Egiaztatu</string>
<string name="section_current_expiry">Oraingo epemuga</string>
<string name="section_new_expiry">Epemuga berria</string>
<!--button-->
<string name="btn_decrypt_verify_file">Dekriptatu, egiaztatu eta gorde agiria</string>
<string name="btn_encrypt_share_file">Enkriptatu eta elkarbanatu agiria</string>
<string name="btn_encrypt_save_file">Enkriptatu eta gorde agiria</string>
+ <string name="btn_save_file">Gorde agiria</string>
+ <string name="btn_save">Gorde</string>
+ <string name="btn_view_log">Ikusi oharra</string>
<string name="btn_do_not_save">Ezeztatu</string>
<string name="btn_delete">Ezabatu</string>
<string name="btn_no_date">Epemuga gabe</string>
@@ -70,6 +76,8 @@
<string name="btn_add_files">Gehitu agiria(k)</string>
<string name="btn_share_decrypted_text">Elkarbanatu dekriptaturiko idazkia</string>
<string name="btn_copy_decrypted_text">Kopiatu dekriptaturiko idazkia</string>
+ <string name="btn_decrypt_clipboard">Irakurri gakotik</string>
+ <string name="btn_decrypt_files">Hautatu sarrera agiria</string>
<string name="btn_encrypt_files">Enkriptatu agiriak</string>
<string name="btn_encrypt_text">Enkriptatu idazkia</string>
<string name="btn_add_email">Gehitu post@ helbide gehigarriak</string>
@@ -93,6 +101,7 @@
<string name="menu_advanced">Argibide Hedatuak</string>
<string name="menu_certify_fingerprint">Baieztatu hatz-aztarna alderaketa bidez</string>
<string name="menu_export_log">Esportatu Oharra</string>
+ <string name="menu_keyserver_add">Gehitu</string>
<!--label-->
<string name="label_message">Idazkia</string>
<string name="label_file">Agiria</string>
@@ -107,16 +116,17 @@
<string name="label_ascii_armor">ASCII Armor agiria</string>
<string name="label_file_ascii_armor">Gaitu ASCII Armor</string>
<string name="label_write_version_header">Jakinarazi besteei OpenKeychain erabiltzen ari zarela</string>
+ <string name="label_write_version_header_summary">\'OpenKeychain v2.7\' idazten du OpenPGP sinadura, idazkia zifratzen du eta giltzak esportatzen ditu</string>
<string name="label_use_default_yubikey_pin">Erabili berezko YubiKey PIN-a</string>
<string name="label_use_num_keypad_for_yubikey_pin">Erabili zenbaki teklatua YubiKey PIN-erako</string>
<string name="label_label_use_default_yubikey_pin_summary">Berezko PIN (123456) erabiltzen du NFC bidezko YubiKeys sarbiderako </string>
- <string name="label_asymmetric_from">Sinatzailea:</string>
<string name="label_to">Enkriptatu hona:</string>
<string name="label_delete_after_encryption">Ezabatu agiriak enkriptatu ondoren</string>
<string name="label_delete_after_decryption">Ezabatu dekriptatu ondoren</string>
<string name="label_encryption_algorithm">Enkriptaketa algoritmoa</string>
<string name="label_hash_algorithm">Hash algoritmoa</string>
<string name="label_symmetric">Enkriptatu sarhitzarekin</string>
+ <string name="label_passphrase_cache_subs">Gogoratu sarhitzak azpigiltzaz</string>
<string name="label_message_compression">Idazki konpresioa</string>
<string name="label_file_compression">Agiri konpresioa</string>
<string name="label_keyservers">Hautatu OpenPGP giltza-zerbitzariak</string>
@@ -134,17 +144,49 @@
<string name="label_send_key">Aldiberetu hodeiarekin</string>
<string name="label_fingerprint">Hatz-aztarna</string>
<string name="expiry_date_dialog_title">Ezarri epemuga eguna</string>
- <string name="label_first_keyserver_is_used">(Zerrendako lehen giltza-zerbitzaria da hobetsia)</string>
+ <string name="label_keyservers_title">Giltza-zerbitzariak</string>
+ <string name="label_keyserver_settings_hint">Arrastatu hurrenkera aldatzeko, ikutu editatu/ezabatzeko</string>
+ <string name="label_selected_keyserver_title">Giltza-zerbitzaria hautatuta</string>
<string name="label_preferred">hobetsia</string>
<string name="label_enable_compression">Gaitu konpresioa</string>
<string name="label_encrypt_filenames">Enkriptatu agirizenak</string>
<string name="label_hidden_recipients">Ezkutatu jasotzaileak</string>
<string name="label_verify_keyserver">Egiaztatu giltza-zerbitzaria</string>
<string name="label_enter_keyserver_url">Sartu giltza-zerbitzariaren URL-a</string>
+ <string name="label_keyserver_dialog_delete">Ezabatu giltza-zerbitzaria</string>
<string name="pref_keyserver">OpenPGP giltza-zerbitzariak</string>
<string name="pref_keyserver_summary">Bilatu giltzak hautaturiko OpenPGP giltza-zerbitzarietan (HKP protokoloa)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Bilatu giltzak keybase.io-an</string>
+ <!--Proxy Preferences-->
+ <string name="pref_proxy_tor_title">Gaitu Tor</string>
+ <string name="pref_proxy_tor_summary">Orbot ezarrita egotea behar du</string>
+ <string name="pref_proxy_normal_title">Gaitu beste proxy bat</string>
+ <string name="pref_proxy_host_title">Proxy Hostalaria</string>
+ <string name="pref_proxy_host_err_invalid">Proxy hostalaria ezin da hutsik egon</string>
+ <string name="pref_proxy_port_title">Proxy Ataka</string>
+ <string name="pref_proxy_port_err_invalid">Ataka zenbaki baliogabea sartu da</string>
+ <string name="pref_proxy_type_title">Proxy Mota</string>
+ <!--proxy type choices and values-->
+ <string name="pref_proxy_type_choice_http">HTTP</string>
+ <string name="pref_proxy_type_choice_socks">SOCKS</string>
+ <string name="pref_proxy_type_value_http">proxyHttp</string>
+ <string name="pref_proxy_type_value_socks">proxySocks</string>
+ <!--OrbotHelper strings-->
+ <string name="orbot_ignore_tor">Ez erabili Tor</string>
+ <!--InstallDialogFragment strings-->
+ <string name="orbot_install_dialog_title">Ezarri Orbot edo erabili Tor?</string>
+ <string name="orbot_install_dialog_install">Ezarri</string>
+ <string name="orbot_install_dialog_content">Orbot ezarrita eta proxy trafiko igaropena gaituta eduki behar duzu. Nahi duzu ezartzea?</string>
+ <string name="orbot_install_dialog_cancel">Ezeztatu</string>
+ <string name="orbot_install_dialog_ignore_tor">Ez erabili Tor</string>
+ <!--StartOrbotDialogFragment strings-->
+ <string name="orbot_start_dialog_title">Abiarazi Orbot?</string>
+ <string name="orbot_start_dialog_content">Ez dirudi Orbot ekinean dagoenik. Nahi duzu abiaraztea eta Tor-era elkartzea?</string>
+ <string name="orbot_start_btn">Abiarazi Orbot</string>
+ <string name="orbot_start_dialog_start">Abiarazi Orbot</string>
+ <string name="orbot_start_dialog_cancel">Ezeztatu</string>
+ <string name="orbot_start_dialog_ignore_tor">Ez erabili Tor</string>
<string name="user_id_no_name">&lt;izen gabe&gt;</string>
<string name="none">&lt;ezer ez&gt;</string>
<plurals name="n_keys">
@@ -192,20 +234,23 @@
<string name="passphrase_for">Sartu \'%s\'-rako sarhitza</string>
<string name="pin_for">Sartu PIN-a \'%s\'-rako</string>
<string name="yubikey_pin_for">Sartu PIN-a YubKey-ra sartzeko \'%s\'-rentzat</string>
- <string name="nfc_text">Jarri YubiKey zure gailuaren atzealdean.</string>
+ <string name="nfc_wait">Eduki YubiKey atzealdean!</string>
<string name="file_delete_confirmation_title">Ezabatu jatorrizko agiriak?</string>
<string name="file_delete_confirmation">Hurrengo agiriak ezabatu egingo dira: %s</string>
<string name="file_delete_successful">%1$d -&gt; %2$d-tik agiri ezbatu dira.%3$s</string>
+ <string name="no_file_selected">Ez da agiririk hautatu</string>
<string name="encrypt_sign_successful">Ongi sinatu eta/edo enkriptatu da.</string>
<string name="encrypt_sign_clipboard_successful">Ongi sinatu eta/edo enkriptatu da gakora.</string>
<string name="select_encryption_key">Hautatu enkriptaketa giltza bat gutxienez.</string>
+ <string name="error_no_encryption_or_signature_key">Hautatu gutxienez enkriptaketa giltza bat edo sinadura giltza bat.</string>
<string name="specify_file_to_encrypt_to">Mesedez adierazi zein agirira enkriptatu.\nKONTUZ: Agiria gainidatzi egingo da egonez gero!</string>
<string name="specify_file_to_decrypt_to">Mesedez adierazi zein agirira dekriptatu.\nKONTUZ: Agiria gainidatzi egingo da egonez gero!</string>
- <string name="specify_file_to_export_to">Mesedez adierazi zein agirira esportatu.\nKONTUZ: Agiria gainidatzi egingo da egonez gero!</string>
+ <string name="specify_backup_dest">Mesedez adierazi zein agirira esportatu.\nKONTUZ: Agiria gainidatzi egingo da egonez gero!</string>
<string name="key_deletion_confirmation_multi">Egitan nahi duzu hautaturiko giltzak ezabatzea?</string>
<string name="secret_key_deletion_confirmation">Ezabatu ondoren ezingo dituzu giltza honekin enkriptatutako mezuak irakurri eta berarekin egindako giltza baieztapen guztiak galduko dira!</string>
<string name="public_key_deletetion_confirmation">Ezabatu \'%s\' giltza?</string>
<string name="also_export_secret_keys">Esportatu giltza sekretuak ere</string>
+ <string name="reinstall_openkeychain">Akats ezagun bat aurkitu duzu Android-rekin. Mesedez ezarri berriro OpenKeychain zure harremanak giltzekin lotzea nahi badituzu.</string>
<string name="key_exported">Ongi esportatu da 1 giltza</string>
<string name="keys_exported">Ongi esportatu dira %d giltza</string>
<string name="no_keys_exported">Ez da giltzarik esportatu.</string>
@@ -286,6 +331,8 @@
<string name="progress_modify_subkeyrevoke">azpigiltzak ukatzen...</string>
<string name="progress_modify_subkeyadd">azpigiltzak gehitzen...</string>
<string name="progress_modify_passphrase">sarhitza aldatzen...</string>
+ <string name="progress_modify_pin">PIN-a aldatzen...</string>
+ <string name="progress_modify_admin_pin">Administrari PIN-a aldatzen...</string>
<plurals name="progress_exporting_key">
<item quantity="one">giltza esportatzen</item>
<item quantity="other">giltzak esportatzen</item>
@@ -359,7 +406,9 @@
<!--Import from URL-->
<string name="import_url_warn_no_search_parameter">Ez da bilaketa eskaerarik zehaztu. Oraindik eskuz bilatu dezakezu giltza-zerbitzari honetan.</string>
<!--Generic result toast-->
+ <string name="snackbar_details">Xehetasunak</string>
<string name="with_warnings">, kontuz oharrekin</string>
+ <string name="with_cancelled">, ezeztatu arte</string>
<!--Import result toast-->
<plurals name="import_keys_added_and_updated_1">
<item quantity="one">Ongi inportatuta 1 giltza</item>
@@ -381,6 +430,10 @@
<item quantity="one">Inportatze hutsegitea 1 giltzarentzat!</item>
<item quantity="other">Inportatze hutsegitea %d giltzentzat!</item>
</plurals>
+ <plurals name="import_error">
+ <item quantity="one">Inportazio hutsegitea!</item>
+ <item quantity="other">Hutsegitea %d giltza inportatzerakoan!</item>
+ </plurals>
<string name="import_error_nothing">Ez dago ezer inportatzeko.</string>
<string name="import_error_nothing_cancelled">Inportazioa ezeztatuta.</string>
<!--Delete result toast-->
@@ -419,7 +472,7 @@
<string name="api_settings_start">Abiarazi aplikazioa</string>
<string name="api_settings_delete_account">Ezabatu kontua</string>
<string name="api_settings_package_name">Pakete Izena</string>
- <string name="api_settings_package_signature">Sinadura Paketearen SHA-256</string>
+ <string name="api_settings_package_certificate">Sinadura Paketearen SHA-256</string>
<string name="api_settings_accounts">Kontuak (API zaharra)</string>
<string name="api_settings_advanced">Argibide Hedatuak</string>
<string name="api_settings_allowed_keys">Ahalbidetutako Giltzak</string>
@@ -435,6 +488,7 @@
<string name="api_select_pub_keys_dublicates_text">Giltza bat baino gehiago dago nortasun hauentzat:</string>
<string name="api_select_pub_keys_text">Mesedz berrikusi jasotzaile zerrenda!</string>
<string name="api_select_pub_keys_text_no_user_ids">Mesedez hautatu jasotzaileak!</string>
+ <string name="api_error_wrong_signature">Sinadura egiaztapen hutsegitea! Aplikazio hau beste iturubur batetik duzu ezarrita? Zihur bazaude hau ez dela eraso bat, ukatu aplikazio honen erregistrazioa OpenKeychain eta orduan erregistratu aplikazioa berriro.</string>
<string name="api_select_sign_key_text">Mesedez hautatu zure giltzetako bat edo sortu berri bat.</string>
<string name="api_select_keys_text">Ahalbidetutako giltza batek ere ezin du edukia dekriptatu. Mesedez hautatu ahalbidetutako giltzak.</string>
<!--Share-->
@@ -549,6 +603,13 @@
<string name="create_key_add_email_text">Post@ helbide gehigarriak ere giltza honekin elkartzen dira eta komunikazio segururako erabili daitezke.</string>
<string name="create_key_email_already_exists_text">Post@ helbidea jadanik gehituta dago</string>
<string name="create_key_email_invalid_email">Post@ heuskarria baliogabea da</string>
+ <string name="create_key_yubi_key_pin_text">Mesedez gogoratu PIN-a, beharrezkoa da gero zure YubiKey erabiltzeko. Mesedez idatzi behean Administrari PIN-a eta biltegiratu toki seguru batean.</string>
+ <string name="create_key_yubi_key_pin">PIN-a</string>
+ <string name="create_key_yubi_key_admin_pin">Administrari PIN-a</string>
+ <string name="create_key_yubi_key_pin_repeat_text">Mesedez sartu PIN-a eta Administrari PIN-a jarraitzeko.</string>
+ <string name="create_key_yubi_key_pin_repeat">Berridatzi PIN-a</string>
+ <string name="create_key_yubi_key_admin_pin_repeat">Berridatzi Administrari PIN-a</string>
+ <string name="create_key_yubi_key_pin_not_correct">PIN-a ez da zuzena!</string>
<!--View key-->
<string name="view_key_revoked">Ukatuta: Giltza ezin da gehiago erabili!</string>
<string name="view_key_expired">Iraungitua: Harremanak giltzaren baliotasuna luzatu behar du!</string>
@@ -557,12 +618,15 @@
<string name="view_key_verified">Baieztatutako Giltza</string>
<string name="view_key_unverified">Baieztatugabe: Eskaneatu QR Kodea giltza baieztatzeko!</string>
<string name="view_key_fragment_no_system_contact">&lt;ezer ez&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Gehitu giltza-zerbitzaria</string>
+ <string name="edit_keyserver_dialog_title">Editatu giltza-zerbitzaria</string>
<string name="add_keyserver_verified">Giltza-zerbitzaria egiaztatuta!</string>
<string name="add_keyserver_without_verification">Giltza-zerbitzaria gehituta egiaztapen gabe.</string>
<string name="add_keyserver_invalid_url">URL baliogabea!</string>
<string name="add_keyserver_connection_failed">Hutsegitea giltza-zerbitzariarekin elkartzerakoan. Mesedez egiaztatu URL-a eta zure internet elkarketa.</string>
+ <string name="keyserver_preference_deleted">%s ezabatuta</string>
+ <string name="keyserver_preference_cannot_delete_last">Ezin da azken giltza-zerbitzaria ezabatu. Gutxienez bat behar da!</string>
<!--Navigation Drawer-->
<string name="nav_keys">Giltzak</string>
<string name="nav_encrypt_decrypt">Enkriptatu/Dekriptatu</string>
@@ -652,6 +716,7 @@
<string name="msg_ip_uid_revoked">Erabiltzaile ID-a ukatua dago</string>
<string name="msg_ip_uat_cert_bad">Egiaztagiri gaitza aurkitu da!</string>
<string name="msg_ip_uat_cert_error">Akatsa egiaztagiria prozesatzerakoan!</string>
+ <string name="msg_ip_uat_cert_nonrevoke">Jadanik badu ez-ukatu egiaztagiri bat, jauzi egiten.</string>
<string name="msg_ip_uat_cert_old">Egiaztagiria aurrekoa baino zaharragoa da, jauzi egiten.</string>
<string name="msg_ip_uat_cert_new">Egiaztagiria berriagoa da, aurrekoa ordezten.</string>
<string name="msg_ip_uat_cert_good">Egiaztagiri ona aurkitu da %1$s-rako</string>
@@ -716,6 +781,8 @@
<string name="msg_mf_master">Maisu egiaztagiriak aldatzen</string>
<string name="msg_mf_notation_pin">PIN jakinarazpen paketea gehitzen</string>
<string name="msg_mf_passphrase">Giltza-uztaiaren sarhitza aldatzen</string>
+ <string name="msg_mf_pin">PIN-a aldatzen txartelean</string>
+ <string name="msg_mf_admin_pin">Administrari PIN-a aldatzen txartelean</string>
<string name="msg_mf_passphrase_key">%s azpigiltza ber-enkriptatzen sarhitz berriarekin</string>
<string name="msg_mf_passphrase_empty_retry">Hutsegitea sarhitz berria ezartzerakoan, berriro saiatzen sarhitz zahar huts batekin</string>
<string name="msg_mf_restricted_mode">Eragiketa modu murriztura aldatzen</string>
@@ -784,7 +851,6 @@
<string name="msg_dc_error_extract_key">Akats ezezaguna giltza desblokeatzerakoan!</string>
<string name="msg_dc_error_integrity_check">Osotasun egiaztapen akatsa!</string>
<string name="msg_dc_error_invalid_data">OpenPGP eduki enkriptatu edo sinatu baliogabea!</string>
- <string name="msg_dc_error_io">SI Salbuespen bat aurkitu da eragiketan zehar!</string>
<string name="msg_dc_error_no_data">Ez da datu enkriptaturik aurkitu jarioan!</string>
<string name="msg_dc_error_no_key">Ez da enkriptatutako daturik giltza sekretu ezagunarekin aurkitu jarioan!</string>
<string name="msg_dc_error_pgp_exception">OpenPGP Salbuespen bat aurkitu da eragiketan zehar!</string>
@@ -798,6 +864,7 @@
<string name="msg_dc">Dekriptaketa eragiketa abiatzen...</string>
<string name="msg_dc_sym_skip">Datu simetrikoak ez daude ahalbidetuta, jauzi egiten...</string>
<string name="msg_dc_unlocking">Giltza sekretua desblokeatzen</string>
+ <string name="msg_dc_old_symmetric_encryption_algo">Potentzialki segurtasun gabea den enkriptaketa algoritmoa erabili da!</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">Sinadura egiaztapena abiatzen</string>
<string name="msg_vl_error_wrong_key">Mezua ez dago giltza zuzenarekin sinatuta</string>
@@ -814,18 +881,24 @@
<string name="msg_se_error_no_input">Ez da sarrerarik eman!</string>
<string name="msg_se_error_input_uri_not_found">Akatsa URI-a irakurtzeko irekitzerakoan!</string>
<string name="msg_se_error_output_uri_not_found">Akatsa URI-a idazteko irekitzerakoan!</string>
+ <string name="msg_se_error_too_many_inputs">Irteera baino sarrera gehiago adierazi dira! Hau zihurrenik programazio akats bat da, mesedez jakinarazi!</string>
<string name="msg_se_success">Sinadura/enkriptaketa eragiketa ongi</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Giltza publikoak gertatzen enkriptaketarako</string>
<string name="msg_pse_compressing">Konpresioa gertatzen</string>
<string name="msg_pse_encrypting">Datuak enkriptatzen</string>
<string name="msg_pse_error_bad_passphrase">Sarhitz gaitza!</string>
+ <string name="msg_pse_error_hash_algo">Eskatutako hash algoritmoa ez dago sostengatuta giltza honetan!</string>
+ <string name="msg_pse_error_io">SI Salbuespen bat aurkitu da eragiketan zehar!</string>
+ <string name="msg_pse_error_key_sign">Hautaturiko sinatze giltzak ezin du daturik sinatu!</string>
<string name="msg_pse_error_sign_key">Akatsa giltza sinatua lortzerakoan!</string>
<string name="msg_pse_error_nfc">NFC datu akatsa!</string>
<string name="msg_pse_error_no_passphrase">Ez da sarhitzik eman!</string>
<string name="msg_pse_error_pgp">Barneko OpenPGP akatsa!</string>
<string name="msg_pse_error_sig">OpenPGP sinadura salbuespena aurkitu da!</string>
<string name="msg_pse_error_unlock">Akats ezezaguna giltza desblokeatzerakoan!</string>
+ <string name="msg_pse_key_ok">Enkriptatzen giltzarako: %s</string>
+ <string name="msg_pse_key_unknown">Ez dago enkriptaketarako giltza: %s</string>
<string name="msg_pse_key_warn">Giltza gaitza enkriptaketarako: %s</string>
<string name="msg_pse_ok">Sinadura/enkriptaketa eragiketa ongi</string>
<string name="msg_pse_pending_nfc">NFC ezagutarazlea beharrezkoa, erabiltzaile sarrera eskatzen...</string>
@@ -843,14 +916,23 @@
<string name="msg_crt">Giltza-uztaiak egiaztagiritzen</string>
<string name="msg_crt_master_fetch">Maisu giltza egiaztagiritua lortzen</string>
<string name="msg_crt_nfc_return">NFC ikusleihora itzultzen</string>
+ <string name="msg_crt_save">%s giltza egiaztagiritua gordetzen</string>
<string name="msg_crt_saving">Giltza-uztaiak gordetzen</string>
<string name="msg_crt_unlock">Maisu giltza desblokeatzen</string>
<string name="msg_crt_success">Nortasunak ongi egiaztagiritu dira</string>
<string name="msg_crt_warn_not_found">Giltza ez da aurkitu!</string>
<string name="msg_crt_warn_cert_failed">Egiaztagiri sortze hutsegitea!</string>
<string name="msg_crt_warn_save_failed">Gordetze eragiketa hutsegitea!</string>
+ <string name="msg_crt_warn_upload_failed">Igoera eragiketa hutsegitea!</string>
<string name="msg_crt_upload_success">Giltza ongi igo da zerbitzarira</string>
+ <plurals name="msg_import">
+ <item quantity="one">Giltza inportatzen</item>
+ <item quantity="other">%d giltza inportatzen</item>
+ </plurals>
<string name="msg_import_fetch_error_decode">Akatsa berreskuratutako giltza-uztai dekodeatzerakoan!</string>
+ <string name="msg_import_fetch_error">Giltza ezin da berreskuratu! (Sare arazoak?)</string>
+ <string name="msg_import_fetch_keybase">keybase.io-tik berreskuratzen: %s</string>
+ <string name="msg_import_fetch_keyserver_error">Ezin da giltza giltza-zerbitzarietatik berreskuratu: %s</string>
<string name="msg_import_fetch_keyserver">Giltza-zerbitzaritik berreskuratzen: %s</string>
<string name="msg_import_fetch_keyserver_ok">Giltza ongi berreskuratu da</string>
<string name="msg_import_keyserver">%s giltza-zerbitzaria erabiltzen</string>
@@ -862,8 +944,14 @@
<string name="msg_import_error_io">Eragiketa hutsegitea s/i akats bategaitik!</string>
<string name="msg_import_partial">Inportatze eragiketa ongi burutu da, akatsekin!</string>
<string name="msg_import_success">Inportatze eragiketa ongi burutu da!</string>
+ <plurals name="msg_export">
+ <item quantity="one">Giltza bat esportatzen</item>
+ <item quantity="other">%d giltza esportatzen</item>
+ </plurals>
<string name="msg_export_all">Giltza guztiak esportatzen</string>
<string name="msg_export_public">Giltza publikoa esportatzen %s</string>
+ <string name="msg_export_upload_public">%s giltza publikoa igotzen</string>
+ <string name="msg_export_secret">%s giltza sekretua esportatzen</string>
<string name="msg_export_error_no_file">Ez da agirizenik adierazi!</string>
<string name="msg_export_error_fopen">Akatsa agiria irekitzen!</string>
<string name="msg_export_error_no_uri">Ez da URI-rik adierazi!</string>
@@ -872,9 +960,15 @@
<string name="msg_export_error_db">Datubase akatsa!</string>
<string name="msg_export_error_io">Sarrera/irteera akatsa!</string>
<string name="msg_export_error_key">Akatsa giltza datuak aurre-prozesatzerakoan!</string>
+ <string name="msg_export_error_upload">Hutsegitea giltza zerbitzara igotzean! Mesedez egiaztatu zure internet elkarketa.</string>
<string name="msg_export_success">Esportatze eragiketa ongi burutu da!</string>
+ <string name="msg_export_upload_success">Giltza-zerbitzarira igotzea ongi!</string>
<string name="msg_del_error_empty">Ez dago ezer ezabatzeko!</string>
<string name="msg_del_error_multi_secret">Giltza sekretuak banaka bakarrik ezabatu daitezke!</string>
+ <plurals name="msg_del">
+ <item quantity="one">Giltza bat ezabatzen</item>
+ <item quantity="other">%d giltza ezabatzen</item>
+ </plurals>
<string name="msg_del_key">%s giltza ezabatzen</string>
<string name="msg_del_key_fail">Hutsegitea %s giltza ezabatzerakoan</string>
<string name="msg_del_consolidate">Datubasea sendotzen giltza sekretua ezabatu ondoren</string>
@@ -882,10 +976,17 @@
<item quantity="one">Ongi ezabatuta giltza</item>
<item quantity="other">Ongi ezabatuta %d giltza</item>
</plurals>
+ <plurals name="msg_del_fail">
+ <item quantity="one">Hutsegitea giltza bat ezabatzerakoan</item>
+ <item quantity="other">Hutsegitea %d giltza ezabatzerakoan</item>
+ </plurals>
<string name="msg_acc_saved">Kontua gordeta</string>
<string name="msg_download_success">Ongi jeitsi da!</string>
<string name="msg_download_no_valid_keys">Ez da baliozko giltzarik aurkitu agiri/gakoan!</string>
<string name="msg_download_query_failed">Akats bat gertatu da giltzak bilatzerakoan.</string>
+ <!--Messages for Keybase Verification operation-->
+ <string name="msg_keybase_error_dns_fail">DNS TXT Grabaketa berreskurapen hutsegitea</string>
+ <string name="msg_keybase_error_specific">%s</string>
<!--Messages for Export Log operation-->
<string name="msg_export_log_start">Esportatze oharra</string>
<string name="msg_export_log_error_fopen">Akatsa agiria irekitzerakoan</string>
@@ -893,6 +994,13 @@
<string name="msg_export_log_error_writing">S/I akatsa agirira idazterakoan!</string>
<string name="msg_export_log_success">Oharra ongi esportatu da!</string>
<!--PassphraseCache-->
+ <string name="passp_cache_notif_click_to_clear">Ikutu sarhitzak garbitzeko</string>
+ <plurals name="passp_cache_notif_n_keys">
+ <item quantity="one">%d sarhitz gogoratuta</item>
+ <item quantity="other">%d sarhitz gogoratuta</item>
+ </plurals>
+ <string name="passp_cache_notif_keys">Gogoratutako sarhitzak</string>
+ <string name="passp_cache_notif_clear">Garbitu Sarhitzak</string>
<string name="passp_cache_notif_pwd">Sarhitza</string>
<!--First Time-->
<string name="first_time_text1">Berreskuratu zure pribatutasuna OpenKeychain-ekin!</string>
@@ -900,11 +1008,19 @@
<string name="first_time_import_key">Inportatu giltza agiritik</string>
<string name="first_time_yubikey">Erabili YubiKey NEO</string>
<string name="first_time_skip">Jauzi Ezarpena</string>
+ <string name="first_time_blank_yubikey">YubiKey huts hau erabiltzea nahi duzu OpenKeychain-ekin?\n\nMesedez irten Yubikey-tik orain, berriro galdetuko zaizu beharrezkoa denean!</string>
+ <string name="first_time_blank_yubikey_yes">Erabili YubiKey hau</string>
<!--unsorted-->
<string name="section_certifier_id">Egiaztatzailea</string>
<string name="section_cert">Egiaztagiriaren Xehetasunak</string>
<string name="label_user_id">Nortasuna</string>
+ <string name="unknown_uid">&lt;ezezaguna&gt;</string>
<string name="empty_certs">Ez dago egiaztagiririk giltza honentzat</string>
+ <string name="certs_text">Hemen balioztatutako berez-egiaztagiriak eta zeure giltzekin sortutako egiaztagiri balioztatuak bakarrik erakusten dira.</string>
+ <string name="section_uids_to_certify">Nortasunak honako</string>
+ <string name="certify_text">Inportatzen ari zaren giltzek \"nortasunak\":izenak eta posta helbideak dituzte. Hautatu zehatz-mehatz hauek itxaroten duzunarekin bat datozela baieztatzeko.</string>
+ <string name="certify_fingerprint_text">Alderatu erakutsitako hatz-aztarnak, hizkiz-hizki, zure gailuko ereduek erakusten duten batekin.</string>
+ <string name="certify_fingerprint_text2">Erakutsitako hatz-aztarnak bat datoz?</string>
<string name="label_revocation">Ukatze Zergaitia</string>
<string name="label_cert_type">Mota</string>
<string name="error_key_not_found">Giltza ez da aurkitu!</string>
@@ -916,9 +1032,13 @@
<string name="unknown_algorithm">ezezaguna</string>
<string name="can_sign_not">ezin da sinatu</string>
<string name="error_no_encrypt_subkey">Ez dago enkriptaketa azpigiltzarik eskuragarri!</string>
+ <string name="account_no_manual_account_creation">Ez sortu OpenKeychain-Kontuak eskuz.\n.Argibide gehiagorako, ikusi Laguntza.</string>
<string name="contact_show_key">Erakutsi (%s) giltza</string>
<string name="swipe_to_update">Irristatu behera giltza-zerbitzaritik eguneratzeko</string>
<string name="error_no_file_selected">Hautatu agiri bat gutxienez enkriptatzeko!</string>
+ <string name="error_multi_files">Agiri ugari gordetzea ez dago sostengatuta. Hau oraingo Androiden muga bat da.</string>
+ <string name="error_multi_clipboard">Agiri anitz gakora enkriptatzea ez dago sostengatuta.</string>
+ <string name="error_detached_signature">Agiri binarioen sinatzea-bakarrik eragiketa ez dago sostengatuta, hautatu gutxienez enkriptaketa giltza bat.</string>
<string name="error_empty_text">Idatzi idazkiren bat enkriptatzeko!</string>
<string name="key_colon">Giltza:</string>
<string name="exchange_description">Giltza trukatzea bat hasteko, hautatu eskuinaldean kide zenbatekoa, orduan sakatu \"Hasi trukatzea\" botoia.\n\nBeste bi galdera egingo zaizkizu kide zuzenek besterik ez dutela eskuhartzen eta beren hatz-aztarnak zuzenak direla zihurtatzeko.</string>
@@ -953,19 +1073,11 @@
<string name="yubikey_serno">Serie Zbk: %s</string>
<string name="yubikey_create">Jarri YubiKey zure gailuaren atzealdean.</string>
<string name="btn_import">Inportatu</string>
+ <string name="snack_yubi_other">Giltza ezberdina biltegiratuta YubiKey-n!</string>
<string name="error_nfc">NFC Akatsa: %s</string>
- <string name="error_pin">NFC: PIN okerra; %d saiakera gelditzen dira.</string>
- <string name="error_nfc_terminated">NFC: Txartel adimentsua amaiera egoeran</string>
- <string name="error_nfc_wrong_length">NFC: Luzer okerra datuak bidaltzeko / jasotzeko</string>
- <string name="error_nfc_conditions_not_satisfied">NFC: Ez dira erabilpen baldaintzak betetzen</string>
- <string name="error_nfc_security_not_satisfied">NFC: Ez da segurtasun egoera betetzen</string>
- <string name="error_nfc_authentication_blocked">NFC: PIN-a blokeatuta saiakera gehiegiren ondoren</string>
- <string name="error_nfc_data_not_found">NFC: Gailtza edo objetua ez da aurkitu</string>
- <string name="error_nfc_unknown">NFC: Akats Ezezaguna</string>
- <string name="error_nfc_bad_data">NFC: Txartelak datu baliogabeak jakinarazi ditu</string>
- <string name="error_nfc_chaining_error">NFC: Txartelak itxaroten azken agindua kate batean</string>
- <string name="error_nfc_header">NFC: Txartelak %s byte baliogabea jakinarazi du</string>
<string name="error_pin_nodefault">Berezko PIN-a baztertua izan da!</string>
+ <string name="error_temp_file">Akatsa aldibaterako agiria sortzerakoan.</string>
+ <string name="btn_delete_original">Ezabatu jatorrizko agiria</string>
<string name="snack_encrypt_filenames_on">Agirizenak enkriptatuta <b>daude</b>.</string>
<string name="snack_encrypt_filenames_off">Agirizenak <b>ez daude</b> enkriptatuta.</string>
<string name="snack_armor_on">Irteera kodeaketa Idazki bezala.</string>
@@ -974,4 +1086,18 @@
<string name="snack_compression_off">Konpresioa <b>ezgaituta</b>.</string>
<string name="error_loading_keys">Akatsa giltzak gertatzerakoan!</string>
<string name="error_empty_log">(akatsa, oharra hutsik)</string>
+ <string name="error_reading_text">Ezin da irakurri sarrera dekriptatzeko!</string>
+ <string name="filename_unknown">&lt;agirizenik ez&gt;</string>
+ <string name="filename_unknown_text">&lt;idazki lau datuak&gt;</string>
+ <string name="intent_show">Erakutsi Sinatutako/Enkriptatutako Edukia</string>
+ <string name="view_internal">Ikusi OpenKeychain-en</string>
+ <string name="error_preparing_data">Akatsa datuak gertatzerakoan!</string>
+ <string name="label_clip_title">Enkriptatutatako Datuak</string>
+ <string name="progress_processing">Prozesatzen...</string>
+ <string name="error_saving_file">Akatsa agiria gordetzerakoan!</string>
+ <string name="file_saved">Agiria gordeta!</string>
+ <string name="file_delete_ok">Jatorrizko agiria ezabatuta.</string>
+ <string name="file_delete_none">Ez da agiria ezabatu! (Jadanik ezabatuta?)</string>
+ <string name="file_delete_exception">Jatorrizko agiria ezin da ezabatu!</string>
+ <string name="error_clipboard_empty">Gakoa hutsik dago!</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-fi/strings.xml b/OpenKeychain/src/main/res/values-fi/strings.xml
index 6b0d7bfb8..724cd7b5c 100644
--- a/OpenKeychain/src/main/res/values-fi/strings.xml
+++ b/OpenKeychain/src/main/res/values-fi/strings.xml
@@ -66,7 +66,6 @@
<string name="label_use_default_yubikey_pin">Käytä vakiota YubiKey PIN:iä</string>
<string name="label_use_num_keypad_for_yubikey_pin">Käytä numeerista näppäimistöä YuniKey PIN:iin</string>
<string name="label_label_use_default_yubikey_pin_summary">Käyttää vakio-PIN:iä (123456) käyttääkseen YubiKeyssejä NFC kautta</string>
- <string name="label_asymmetric_from">Allekirjoittaja:</string>
<string name="label_to">Salaa:</string>
<string name="label_delete_after_decryption">Poista salauksen purkamisen jälkeen</string>
<string name="label_encryption_algorithm">Salausalgoritmi</string>
@@ -85,8 +84,12 @@
<string name="label_send_key">Synkronoi pilveen</string>
<string name="label_fingerprint">Sormenjälki</string>
<string name="expiry_date_dialog_title">Aseta umpeutumispäivämäärä</string>
- <string name="label_first_keyserver_is_used">(Ensimmäinen avainpalvelin listalla on ensisijainen)</string>
<string name="label_preferred">ensisijainen</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;ei nimeä&gt;</string>
<string name="none">&lt;ei mitään&gt;</string>
<plurals name="n_keys">
@@ -161,7 +164,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -180,6 +183,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index d5210379e..96e7b9aba 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -35,7 +35,7 @@
<string name="title_manage_my_keys">Gérer mes clefs</string>
<!--section-->
<string name="section_user_ids">identités</string>
- <string name="section_yubikey">Clef Yubi</string>
+ <string name="section_yubikey">ClefYubi</string>
<string name="section_linked_system_contact">Contact système relié</string>
<string name="section_should_you_trust">Devriez-vous faire confiance à cette clef ?</string>
<string name="section_proof_details">Vérification de preuve</string>
@@ -56,6 +56,8 @@
<string name="btn_decrypt_verify_file">Déchiffrer, vérifier et enregistrer le fichier</string>
<string name="btn_encrypt_share_file">Chiffrer et partager le fichier</string>
<string name="btn_encrypt_save_file">Chiffrer et enregistrer un fichier</string>
+ <string name="btn_save_file">Enregistrer le fichier</string>
+ <string name="btn_save">Enregistrer</string>
<string name="btn_view_log">Visualiser le journal</string>
<string name="btn_do_not_save">Annuler</string>
<string name="btn_delete">Supprimer</string>
@@ -98,6 +100,7 @@
<string name="menu_advanced">Informations détaillées</string>
<string name="menu_certify_fingerprint">Confirmer par une comparaison d\'empreinte</string>
<string name="menu_export_log">Exporter le journal</string>
+ <string name="menu_keyserver_add">Ajouter</string>
<!--label-->
<string name="label_message">Texte</string>
<string name="label_file">Fichier</string>
@@ -113,10 +116,9 @@
<string name="label_file_ascii_armor">Activer l\'armure ASCII</string>
<string name="label_write_version_header">Faire savoir aux autres que vous utilisez OpenKeychain</string>
<string name="label_write_version_header_summary">Ajoute « OpenKeychain v2.7 » aux signatures OpenPGP, aux cryptogrammes et aux clefs exportées</string>
- <string name="label_use_default_yubikey_pin">Utiliser le NIP par défaut de la clef Yubi</string>
- <string name="label_use_num_keypad_for_yubikey_pin">Utiliser le pavé numérique pour le NIP de la clef Yubi</string>
- <string name="label_label_use_default_yubikey_pin_summary">Utilise le NIP par défaut (123456) pour accéder aux clefs Yubi par la NFC</string>
- <string name="label_asymmetric_from">Signé par :</string>
+ <string name="label_use_default_yubikey_pin">Utiliser le NIP par défaut de la ClefYubi</string>
+ <string name="label_use_num_keypad_for_yubikey_pin">Utiliser le pavé numérique pour le NIP de la ClefYubi</string>
+ <string name="label_label_use_default_yubikey_pin_summary">Utilise le NIP par défaut (123456) pour accéder aux ClefsYubi par la NFC</string>
<string name="label_to">Chiffrer pour :</string>
<string name="label_delete_after_encryption">Supprimer les fichiers après chiffrement</string>
<string name="label_delete_after_decryption">Supprimer le fichier après le déchiffrement</string>
@@ -142,17 +144,25 @@
<string name="label_send_key">Synchroniser avec le nuage</string>
<string name="label_fingerprint">Empreinte</string>
<string name="expiry_date_dialog_title">Définir une date d\'expiration</string>
- <string name="label_first_keyserver_is_used">(Le premier serveur de clefs listé est préféré)</string>
+ <string name="label_keyservers_title">Serveurs de clefs</string>
+ <string name="label_keyserver_settings_hint">Glisser pour changer l\'ordre, toquer pour éditer/supprimer</string>
+ <string name="label_selected_keyserver_title">Serveurs de clefs sélectionnés</string>
<string name="label_preferred">préféré</string>
<string name="label_enable_compression">Activer la compression</string>
<string name="label_encrypt_filenames">Chiffrer les nom de fichier</string>
<string name="label_hidden_recipients">Cacher les destinataires</string>
<string name="label_verify_keyserver">Vérifier le serveur de clefs</string>
<string name="label_enter_keyserver_url">Saisir l\'URL du serveur de clefs</string>
+ <string name="label_keyserver_dialog_delete">Supprimer le serveur de clefs</string>
<string name="pref_keyserver">Serveurs de clefs OpenPGP</string>
<string name="pref_keyserver_summary">Rechercher les clefs dans les serveurs de clefs OpenPGP choisis (protocole HKP)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Rechercher les clefs sur keybase.io</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;aucun nom&gt;</string>
<string name="none">&lt;aucune&gt;</string>
<plurals name="n_keys">
@@ -199,8 +209,8 @@
<string name="passphrase_for_symmetric_encryption">Chriffrement symétrique.</string>
<string name="passphrase_for">Saisir le mot de passe pour « %s »</string>
<string name="pin_for">Saisir le NIP pour « %s »</string>
- <string name="yubikey_pin_for">Saisir le NIP pour accéder à la clef Yubi pour « %s »</string>
- <string name="nfc_text">Tenez la clef Yubi contre le dos de votre appareil.</string>
+ <string name="yubikey_pin_for">Saisir le NIP pour accéder à la ClefYubi pour « %s »</string>
+ <string name="nfc_text">Tenez la ClefYubi contre le logo NFC au dos de votre appareil.</string>
<string name="file_delete_confirmation_title">Supprimer les fichiers originaux ?</string>
<string name="file_delete_confirmation">Les fichiers suivants seront détruits : %s</string>
<string name="file_delete_successful">%1$d fichiers sur %2$d ont déjà été supprimés. %3$s</string>
@@ -211,7 +221,7 @@
<string name="error_no_encryption_or_signature_key">Choisir au moins une clef de chiffrement ou une clef de signature.</string>
<string name="specify_file_to_encrypt_to">Veuillez spécifier vers quel fichier chiffrer.\nAVERTISSEMENT : le fichier sera écrasé s\'il existe !</string>
<string name="specify_file_to_decrypt_to">Veuillez spécifier vers quel fichier déchiffrer.\nAVERTISSEMENT : le fichier sera écrasé s\'il existe !</string>
- <string name="specify_file_to_export_to">Veuillez spécifier vers quel fichier exporter.\nAVERTISSEMENT : le fichier sera écrasé s\'il existe !</string>
+ <string name="specify_backup_dest">Veuillez spécifier vers quel fichier exporter.\nAVERTISSEMENT : le fichier sera écrasé s\'il existe !</string>
<string name="key_deletion_confirmation_multi">Voulez-vous vraiment supprimer toutes les clefs sélectionnées ?</string>
<string name="secret_key_deletion_confirmation">Après suppression vous ne pourrez plus lire les messages chiffrés avec cette clef et vous perdrez toutes les confirmations de clefs faites avec elle !</string>
<string name="public_key_deletetion_confirmation">Supprimer la clef \'%s\' ?</string>
@@ -258,7 +268,7 @@
<string name="error_beam_needed">Beam doit être activé !</string>
<string name="error_nothing_import">Aucune clef trouvée !</string>
<string name="error_nothing_import_selected">Aucune clef sélectionnée pour l\'importation !</string>
- <string name="error_contacts_key_id_missing">Échec lors de la récupération de l\'ID de clef à partir des contacts !</string>
+ <string name="error_contacts_key_id_missing">Échec de récupération de l\'ID de clef des contacts !</string>
<string name="error_generic_report_bug">Une erreur générique est survenue, veuillez créer un nouveau rapport de bogue pour OpenKeychain.</string>
<!--results shown after decryption/verification-->
<string name="decrypt_result_no_signature">Non signé</string>
@@ -304,6 +314,8 @@
<string name="progress_modify_subkeystrip">dépouillement des sous-clefs...</string>
<string name="progress_modify_subkeyadd">ajout des sous-clefs...</string>
<string name="progress_modify_passphrase">modification du mot passe...</string>
+ <string name="progress_modify_pin">changement du NIP...</string>
+ <string name="progress_modify_admin_pin">changement du NIP d\'admin....</string>
<plurals name="progress_exporting_key">
<item quantity="one">exportation de la clef...</item>
<item quantity="other">exportation des clefs...</item>
@@ -413,8 +425,8 @@
<item quantity="other">%1$d clefs ont été supprimées avec succès</item>
</plurals>
<plurals name="delete_ok_but_fail_2">
- <item quantity="one">, mais échec lors de la suppression d\'une key%2$s.</item>
- <item quantity="other">, mais échec lors de la suppression de %1$d key%2$s.</item>
+ <item quantity="one">, mais échec de suppression d\'une key%2$s.</item>
+ <item quantity="other">, mais échec de suppression de %1$d key%2$s.</item>
</plurals>
<plurals name="delete_ok">
<item quantity="one">Une key%2$s supprimée avec succès.</item>
@@ -459,7 +471,7 @@
<string name="api_settings_start">Lancer l\'application</string>
<string name="api_settings_delete_account">Supprimer le compte</string>
<string name="api_settings_package_name">Nom du paquet</string>
- <string name="api_settings_package_signature">SHA-256 de la signature du paquet</string>
+ <string name="api_settings_package_certificate">SHA-256 de la signature du paquet</string>
<string name="api_settings_accounts">Comptes (ancienne API)</string>
<string name="api_settings_advanced">Informations détaillées</string>
<string name="api_settings_allowed_keys">Clefs autorisées</string>
@@ -536,7 +548,7 @@
<string name="keybase_unknown_proof_failure">Problème inconnu avec le vérificateur de preuve</string>
<string name="keybase_problem_fetching_evidence">Problème avec la preuve</string>
<string name="keybase_key_mismatch">L\'empreinte de clef ne correspondant pas à celle du billet de preuve</string>
- <string name="keybase_dns_query_failure">Échec lors de la récupération de l\'enregistrement DNS TXT</string>
+ <string name="keybase_dns_query_failure">Échec de récupération de l\'enregistrement DNS TXT</string>
<string name="keybase_no_prover_found">Aucun vérificateur de preuve trouvé pour</string>
<string name="keybase_message_payload_mismatch">Le billet de preuve déchiffré ne correspond pas à la valeur attendue</string>
<string name="keybase_message_fetching_data">Récupération de la preuve</string>
@@ -570,7 +582,7 @@
<item>Changer l\'expiration</item>
<item>Révoquer la sous-clef</item>
<item>Dépouiller la sous-clef</item>
- <item>Déplacer la sous-clef vers la clef Yubi / carte à puce</item>
+ <item>Déplacer la sous-clef vers la ClefYubi / carte à puce</item>
</string-array>
<string name="edit_key_new_subkey">nouvelle sous-clef</string>
<string name="edit_key_select_flag">Veuillez sélectionner au moins un drapeau !</string>
@@ -596,6 +608,13 @@
<string name="create_key_add_email_text">Des adresses courriel supplémentaires sont aussi associées à cette clef et peuvent être utilisées pour des communications sécurisées.</string>
<string name="create_key_email_already_exists_text">L\'adresse courriel a déjà été ajoutée</string>
<string name="create_key_email_invalid_email">Le format de l\'adresse courriel est invalide</string>
+ <string name="create_key_yubi_key_pin_text">Veuillez mémoriser le NIP. Il sera exigé pour une utilisation ultérieure de votre ClefYubi. Prenez si possible le NIP d\'admin. en note et stockez-le dans un endroit sûr</string>
+ <string name="create_key_yubi_key_pin">NIP</string>
+ <string name="create_key_yubi_key_admin_pin">NIP d\'admin.</string>
+ <string name="create_key_yubi_key_pin_repeat_text">Veuillez saisir le NIP et le NIP d\'admin. pour continuer.</string>
+ <string name="create_key_yubi_key_pin_repeat">Répéter le NIP</string>
+ <string name="create_key_yubi_key_admin_pin_repeat">Répéter le NIP d\'admin.</string>
+ <string name="create_key_yubi_key_pin_not_correct">NIP erroné !</string>
<!--View key-->
<string name="view_key_revoked">Révoquée : la clef ne doit plus être utilisée !</string>
<string name="view_key_expired">Expirée : le contact doit prolonger la validité de la clef !</string>
@@ -604,12 +623,15 @@
<string name="view_key_verified">Clef confirmée</string>
<string name="view_key_unverified">Non confirmée : lisez le code QR pour confirmer la clef !</string>
<string name="view_key_fragment_no_system_contact">&lt;aucun&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Ajouter un serveur de clefs</string>
+ <string name="edit_keyserver_dialog_title">Modifier le serveur de clefs</string>
<string name="add_keyserver_verified">Le serveur de clefs a été vérifié !</string>
<string name="add_keyserver_without_verification">Le serveur de clefs a été ajouté sans vérification.</string>
<string name="add_keyserver_invalid_url">URL invalide !</string>
<string name="add_keyserver_connection_failed">Échec de connexion au serveur de clefs. Veuillez vérifier l\'URL et votre connexion Internet.</string>
+ <string name="keyserver_preference_deleted">%s supprimé</string>
+ <string name="keyserver_preference_cannot_delete_last">Impossible de supprimer le dernier serveur de clefs. Il en faut au moins un !</string>
<!--Navigation Drawer-->
<string name="nav_keys">Clefs</string>
<string name="nav_encrypt_decrypt">Chiffrer/déchiffrer</string>
@@ -868,8 +890,10 @@
<string name="msg_mf_notation_empty">Ajout d\'un paquet de notation vide</string>
<string name="msg_mf_notation_pin">Ajout d\'un paquet de notation NIP</string>
<string name="msg_mf_passphrase">Changement de mot de passe pour le trousseau</string>
+ <string name="msg_mf_pin">Changement du NIP sur la carte</string>
+ <string name="msg_mf_admin_pin">Changement du NIP d\'admin. sur la carte</string>
<string name="msg_mf_passphrase_key">Rechiffrement de la sous-clef %s avec un nouveau mot de passe</string>
- <string name="msg_mf_passphrase_empty_retry">Échec lors de la définition du nouveau mot de passe, nouvel essai avec un ancien mot de passe vide</string>
+ <string name="msg_mf_passphrase_empty_retry">Échec de définition du nouveau mot de passe, nouvel essai avec un ancien mot de passe vide</string>
<string name="msg_mf_passphrase_fail">Le mot de passe de la sous-clef n\'a pas pu être changé ! (Est-il différent des autres clefs ?)</string>
<string name="msg_mf_primary_replace_old">Remplacement du certificat de l\'ID utilisateur principal précédent</string>
<string name="msg_mf_primary_new">Génération d\'un nouveau certificat pour le nouvel ID utilisateur principal</string>
@@ -924,8 +948,8 @@
<item quantity="other">Réimportation de %d clefs secrètes</item>
</plurals>
<string name="msg_con_reimport_secret_skip">Aucune clef secrète à réimporter, étape ignorée...</string>
- <string name="msg_con_warn_delete_public">Une exception a eu lieu lors de la suppression du fichier de cache public</string>
- <string name="msg_con_warn_delete_secret">Une exception a eu lieu lors de la suppression du fichier de cache secret</string>
+ <string name="msg_con_warn_delete_public">Exception de suppression du fichier de cache public</string>
+ <string name="msg_con_warn_delete_secret">Exception de suppression du fichier de cache secret</string>
<!--Edit Key (higher level than modify)-->
<string name="msg_ed">Exécution de l\'opération sur la clef</string>
<string name="msg_ed_caching_new">Mise en cache du nouveau mot de passe</string>
@@ -939,7 +963,7 @@
<string name="msg_pr_error_key_not_found">Clef introuvable !</string>
<string name="msg_pr_fetching">Obtention de la clef à modifier (%s)</string>
<string name="msg_pr_subkey_match">Promotion de la sous-clef : %s</string>
- <string name="msg_pr_subkey_nomatch">La sous-clef n\'est pas sur la clef Yubi : %s</string>
+ <string name="msg_pr_subkey_nomatch">La sous-clef n\'est pas sur la ClefYubi : %s</string>
<string name="msg_pr_success">Clef promue avec succès</string>
<!--Other messages used in OperationLogs-->
<string name="msg_ek_error_dummy">Impossible de modifier un trousseau avec une clef maîtresse dépouillée !</string>
@@ -968,7 +992,6 @@
<string name="msg_dc_error_integrity_check">Erreur de vérification de l\'intégrité !</string>
<string name="msg_dc_error_integrity_missing">Vérification de l\'intégrité absente ! Ceci peut arriver car l\'application n\'est pas à jour, ou à cause d\'une attaque par mise à niveau inférieur.</string>
<string name="msg_dc_error_invalid_data">Aucune donnée OpenPGP valide chiffrée ou signée n\'a été trouvée !</string>
- <string name="msg_dc_error_io">Une exception E/S a été rencontrée durant l\'opération !</string>
<string name="msg_dc_error_no_data">Aucune donnée chiffrée n\'a été trouvée dans le flux !</string>
<string name="msg_dc_error_no_key">Aucune donnée chiffrée avec une clef secrète connue n\'a été trouvée dans le flux !</string>
<string name="msg_dc_error_pgp_exception">Une exception OpenPGP a été rencontrée durant l\'opération !</string>
@@ -1056,8 +1079,8 @@
<string name="msg_crt_unlock">Déverrouillage de la clef maîtresse</string>
<string name="msg_crt_success">Identités certifiées avec succès</string>
<string name="msg_crt_warn_not_found">Clef introuvable !</string>
- <string name="msg_crt_warn_cert_failed">Échec lors de la génération du certificat !</string>
- <string name="msg_crt_warn_save_failed">Échec lors de l\'opération d\'enregistrement !</string>
+ <string name="msg_crt_warn_cert_failed">Échec de génération du certificat !</string>
+ <string name="msg_crt_warn_save_failed">Échec de l\'opération d\'enregistrement !</string>
<string name="msg_crt_upload_success">Clef téléversée vers le serveur avec succès</string>
<plurals name="msg_import">
<item quantity="one">Importation de la clef</item>
@@ -1074,7 +1097,7 @@
<string name="msg_import_fingerprint_ok">Vérification de l\'empreinte OK !</string>
<string name="msg_import_merge">Fusion des données récupérées</string>
<string name="msg_import_merge_error">Erreur de fusion des données récupérées !</string>
- <string name="msg_import_error">Échec lors de l\'opération d\'importation !</string>
+ <string name="msg_import_error">Échec de l\'opération d\'importation !</string>
<string name="msg_import_error_io">Échec de l\'opération causé par une erreur d\'E/S !</string>
<string name="msg_import_partial">Opération d\'importation réussie, avec des erreurs !</string>
<string name="msg_import_success">Opération d\'importation réussie !</string>
@@ -1101,15 +1124,15 @@
<item quantity="other">Suppression de %d clefs</item>
</plurals>
<string name="msg_del_key">Suppression de la clef %s</string>
- <string name="msg_del_key_fail">Échec lors de la suppression de la clef %s</string>
+ <string name="msg_del_key_fail">Échec de suppression de la clef %s</string>
<string name="msg_del_consolidate">Consolidation de la base de données après la suppression de la clef secrète</string>
<plurals name="msg_del_ok">
<item quantity="one">Suppression de la clef réussie</item>
<item quantity="other">Suppression de %d clefs réussie</item>
</plurals>
<plurals name="msg_del_fail">
- <item quantity="one">Échec lors de la suppression d\'une clef</item>
- <item quantity="other">Échec lors de la suppression de %d clefs</item>
+ <item quantity="one">Échec de suppression d\'une clef</item>
+ <item quantity="other">Échec de suppression de %d clefs</item>
</plurals>
<string name="msg_acc_saved">Compte enregistré</string>
<string name="msg_download_success">Téléchargement réussi !</string>
@@ -1123,6 +1146,14 @@
<string name="msg_download_too_many_responses">La requête de recherche de clef a retourné trop de candidats. Veuillez raffiner votre requête !</string>
<string name="msg_download_query_too_short_or_too_many_responses">Soit aucune clef ou trop de clefs ont été trouvées. Veuillez améliorer votre requête !</string>
<string name="msg_download_query_failed">Une erreur est survenue lors de la recherche de clefs.</string>
+ <!--Messages for Keybase Verification operation-->
+ <string name="msg_keybase_verification">Tentative de vérification « keybase » pour %s</string>
+ <string name="msg_keybase_error_no_prover">Aucun vérificateur de preuve trouvé pour %s</string>
+ <string name="msg_keybase_error_fetching_evidence">Problème de récupération de la preuve</string>
+ <string name="msg_keybase_error_key_mismatch">L\'empreinte de la clef ne correspond pas à celle du billet de preuve</string>
+ <string name="msg_keybase_error_dns_fail">Échec de récupération de l\'enregistrement DNS TXT</string>
+ <string name="msg_keybase_error_specific">%s</string>
+ <string name="msg_keybase_error_msg_payload_mismatch">Le billet de preuve déchiffré ne correspond pas à la valeur attendue</string>
<!--Messages for Export Log operation-->
<string name="msg_export_log_start">Exportation du journal</string>
<string name="msg_export_log_error_fopen">Erreur d\'ouverture du fichier !</string>
@@ -1142,8 +1173,10 @@
<string name="first_time_text1">Reprenez le contrôle de votre vie privée avec OpenKeychain |</string>
<string name="first_time_create_key">Créer ma clef</string>
<string name="first_time_import_key">Importer la clef d\'un fichier</string>
- <string name="first_time_yubikey">Utiliser le NEO de la clef Yubi</string>
+ <string name="first_time_yubikey">Utiliser le NEO de la ClefYubi</string>
<string name="first_time_skip">Ignorer le paramétrage</string>
+ <string name="first_time_blank_yubikey">Voulez-vous utiliser cette ClefYubi NEO vide avec OpenKeychain ?\n\nVeuillez retirer la ClefYubi maintenant, vous serez informé quand elle sera requise de nouveau !</string>
+ <string name="first_time_blank_yubikey_yes">Utiliser cette ClefYubi</string>
<!--unsorted-->
<string name="section_certifier_id">Certificateur</string>
<string name="section_cert">Détails du certificat</string>
@@ -1168,7 +1201,7 @@
<string name="unknown_algorithm">inconnu</string>
<string name="can_sign_not">impossible de signer</string>
<string name="error_no_encrypt_subkey">Aucune sous-clef de chiffrement n\'est proposée !</string>
- <string name="info_no_manual_account_creation">Ne pas créer de comptes-OpenKeychain manuellement.\nPour plus d\'informations, consultez l\'Aide.</string>
+ <string name="account_no_manual_account_creation">Ne pas créer de comptes-OpenKeychain manuellement.\nPour plus d\'informations, consultez l\'Aide.</string>
<string name="contact_show_key">Montrer la clef (%s)</string>
<string name="swipe_to_update">Glisser vers le bas pour mettre à jour à partir du serveur de clefs</string>
<string name="error_no_file_selected">Choisir au moins un fichier à chiffrer !</string>
@@ -1212,25 +1245,15 @@
<string name="yubikey_serno">No de série : %s</string>
<string name="yubikey_key_holder">Détenteur de la clef :</string>
<string name="yubikey_key_holder_not_set">Détenteur de la clef : &lt;not set&gt;</string>
- <string name="yubikey_status_bound">La clef Yubi correspond et est reliée à la clef</string>
- <string name="yubikey_status_unbound">La clef Yubi correspond et peut être reliée à la clef</string>
- <string name="yubikey_status_partly">La clef Yubi correspond et est partiellement reliée à la clef</string>
- <string name="yubikey_create">Tenez la clef Yubi contre le dos de votre appareil.</string>
+ <string name="yubikey_status_bound">La ClefYubi correspond et est reliée à la clef</string>
+ <string name="yubikey_status_unbound">La ClefYubi correspond et peut être reliée à la clef</string>
+ <string name="yubikey_status_partly">La ClefYubi correspond et est partiellement reliée à la clef</string>
+ <string name="yubikey_create">Tenez la ClefYubi contre le dos de votre appareil.</string>
<string name="btn_import">Importer</string>
- <string name="snack_yubi_other">Une clef différente est stockée sur la clef Yubi !</string>
+ <string name="snack_yubi_other">Une clef différente est stockée sur la ClefYubi !</string>
<string name="error_nfc">Erreur NFC ; %s</string>
- <string name="error_pin">NFC : NIP erroné ; il reste %d essais.</string>
- <string name="error_nfc_terminated">NFC : carte à puce en état de fin d\'opération</string>
- <string name="error_nfc_wrong_length">NFC : longueur erronée de données envoyées / reçues</string>
- <string name="error_nfc_conditions_not_satisfied">NFC : les conditions d\'utilisation ne sont pas satisfaites</string>
- <string name="error_nfc_security_not_satisfied">NFC : l\'état de sécurité n\'est pas satisfait</string>
- <string name="error_nfc_authentication_blocked">NFC : NIP bloqué après trop d\'essais</string>
- <string name="error_nfc_data_not_found">NFC : clef ou objet introuvable</string>
- <string name="error_nfc_unknown">NFC : erreur inconnue</string>
- <string name="error_nfc_bad_data">NFC : la carte a signalé des données invalides</string>
- <string name="error_nfc_chaining_error">NFC : la carte attendait la dernière commande dans une chaîne</string>
- <string name="error_nfc_header">NFC : la carte a signalé %s bytes invalides</string>
<string name="error_pin_nodefault">Le NIP par défaut a été rejeté !</string>
+ <string name="error_temp_file">Erreur de création du fichier temporaire.</string>
<string name="btn_delete_original">Supprimer le fichier original</string>
<string name="snack_encrypt_filenames_on">Les noms de fichiers <b>sont</b> chiffrés.</string>
<string name="snack_encrypt_filenames_off">Les noms de fichiers <b>ne sont pas</b> chiffrés.</string>
@@ -1253,4 +1276,5 @@
<string name="file_delete_ok">Fichier original supprimé.</string>
<string name="file_delete_none">Aucun fichier supprimé (déjà supprimé ?)</string>
<string name="file_delete_exception">Impossible de supprimer le fichier original !</string>
+ <string name="error_clipboard_empty">Le presse-papiers est vide !</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-is/strings.xml b/OpenKeychain/src/main/res/values-is/strings.xml
index 8f84af665..0713e39ad 100644
--- a/OpenKeychain/src/main/res/values-is/strings.xml
+++ b/OpenKeychain/src/main/res/values-is/strings.xml
@@ -7,6 +7,11 @@
<!--button-->
<!--menu-->
<!--label-->
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<!--choice-->
<!--key flags-->
<!--sentences-->
@@ -42,7 +47,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -61,6 +66,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index 3e05ffe2c..9a479c947 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -37,6 +37,8 @@
<string name="section_user_ids">Identità</string>
<string name="section_yubikey">YubiKey</string>
<string name="section_should_you_trust">Ci si potrà fidare di questa chiave?</string>
+ <string name="section_proof_details">Verifica prova</string>
+ <string name="section_cloud_evidence">Prova dalla cloud</string>
<string name="section_keys">Sottochiavi</string>
<string name="section_cloud_search">Ricerca</string>
<string name="section_passphrase_cache">Trattamento Password/PIN</string>
@@ -53,6 +55,8 @@
<string name="btn_decrypt_verify_file">Decodifica, verifica e salva su file</string>
<string name="btn_encrypt_share_file">Codifica e condividi file</string>
<string name="btn_encrypt_save_file">Codifica e salva file</string>
+ <string name="btn_save_file">Salva file</string>
+ <string name="btn_save">Salva</string>
<string name="btn_view_log">Mostra log</string>
<string name="btn_do_not_save">Annulla</string>
<string name="btn_delete">Elimina</string>
@@ -95,6 +99,7 @@
<string name="menu_advanced">Informazioni avanzate</string>
<string name="menu_certify_fingerprint">Confermare tramite il confronto delle impronte digitali</string>
<string name="menu_export_log">Esporta log</string>
+ <string name="menu_keyserver_add">Aggiungi</string>
<!--label-->
<string name="label_message">Testo</string>
<string name="label_file">File</string>
@@ -113,7 +118,6 @@
<string name="label_use_default_yubikey_pin">Utilizza il PIN predefinito di YubiKey</string>
<string name="label_use_num_keypad_for_yubikey_pin">Utilizza la tastiera numerica per il PIN di YubiKey</string>
<string name="label_label_use_default_yubikey_pin_summary">Usa PIN predefinito (123456) per accedere YubiKeys tramite NFC</string>
- <string name="label_asymmetric_from">Firmato da:</string>
<string name="label_to">Codifica per:</string>
<string name="label_delete_after_encryption">Elimina file dopo la codifica</string>
<string name="label_delete_after_decryption">Elimina dopo la decodifica</string>
@@ -139,15 +143,25 @@
<string name="label_send_key">Sincronizza con il cloud</string>
<string name="label_fingerprint">Impronta</string>
<string name="expiry_date_dialog_title">Impostare la data di scadenza</string>
- <string name="label_first_keyserver_is_used">(Primo server delle chiavi elencato è il preferito)</string>
+ <string name="label_keyservers_title">Server chiavi</string>
+ <string name="label_keyserver_settings_hint">Trascina per cambiare ordine, toccare per modificare/cancellare</string>
+ <string name="label_selected_keyserver_title">Server chiavi scelto</string>
<string name="label_preferred">preferiti</string>
<string name="label_enable_compression">Abilitare compressione</string>
<string name="label_encrypt_filenames">Codifica nome dei file</string>
<string name="label_hidden_recipients">Nascondi destinatari</string>
<string name="label_verify_keyserver">Verificare server chiavi</string>
<string name="label_enter_keyserver_url">Inserisci URL server chiavi</string>
+ <string name="label_keyserver_dialog_delete">Cancella server chiavi</string>
<string name="pref_keyserver">Server chiavi OpenPGP</string>
<string name="pref_keyserver_summary">Cerca chiavi su server chiavi OpenPGP selezionati (protocollo HKP)</string>
+ <string name="pref_keybase">keybase.io</string>
+ <string name="pref_keybase_summary">Ricerca chiavi su keybase.io</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;nessun nome&gt;</string>
<string name="none">&lt;nessuno&gt;</string>
<plurals name="n_keys">
@@ -187,11 +201,28 @@
<string name="flag_encrypt">Codifica</string>
<string name="flag_authenticate">Convalida</string>
<!--sentences-->
+ <string name="wrong_passphrase">Password errata</string>
<string name="no_filemanager_installed">Nessun gestore file compatibile installato.</string>
+ <string name="passphrases_do_not_match">Le password non corrispondono.</string>
+ <string name="passphrase_must_not_be_empty">Si prega di inserire una password.</string>
<string name="passphrase_for_symmetric_encryption">Codifica Simmetrica.</string>
+ <string name="passphrase_for">Inserisci la password per \'%s\'</string>
+ <string name="pin_for">Inserisci il PIN per \'%s\'</string>
+ <string name="yubikey_pin_for">Inserisci il PIN per accedere a YubiKey con \'%s\'</string>
+ <string name="file_delete_confirmation_title">Eliminare i file originali?</string>
+ <string name="file_delete_confirmation">I seguenti file verranno cancellati:%s</string>
+ <string name="file_delete_successful">%1$d di %2$d file sono stati cancellati.%3$s</string>
+ <string name="no_file_selected">Nessun file selezionato.</string>
<string name="encrypt_sign_successful">Firmato e/o codificato con successo.</string>
<string name="encrypt_sign_clipboard_successful">Firmato e/o codificato con successo negli appunti.</string>
<string name="select_encryption_key">Seleziona almeno una chiave di codifica.</string>
+ <string name="error_no_encryption_or_signature_key">Selezionare almeno una chiave per la cifratura o una chiave per la firma.</string>
+ <string name="specify_file_to_encrypt_to">Per favore specifica il file da codificare entro.\nATTENZIONE: Il file sarà sovrascritto se esistente.</string>
+ <string name="specify_file_to_decrypt_to">Per favore specifica il file da decifrare entro.\nATTENZIONE: Il file sarà sovrascritto se esistente.</string>
+ <string name="specify_backup_dest">Per favore specifica il file da esportare entro.\nATTENZIONE: Il file sarà sovrascritto se esistente.</string>
+ <string name="key_deletion_confirmation_multi">Vuoi veramente eliminare tutte le chiavi selezionate?</string>
+ <string name="secret_key_deletion_confirmation">Dopo la cancellazione non sarai in grado di leggere i messaggi cifrati con questa chiave e perderai tutte le conferme principali fatti con essa!</string>
+ <string name="public_key_deletetion_confirmation">Elimnina chiave \'%s\'?</string>
<string name="also_export_secret_keys">Esporta anche chiave segreta</string>
<string name="reinstall_openkeychain">Hai riscontrato un bug noto con Android. Si prega di reinstallare OpenKeychain se vuoi collegare i tuoi contatti con le chiavi.</string>
<string name="key_exported">1 chiave esportata correttamente.</string>
@@ -199,6 +230,7 @@
<string name="no_keys_exported">Nessuna chiave esportata.</string>
<string name="key_creation_el_gamal_info">Nota: supporto sottochiavi solo per ElGamal.</string>
<string name="key_not_found">Impossibile trovare la chiave %08X.</string>
+ <string name="specify_file_to_export_log_to">Per favore specifica il file da esportare entro.\nATTENZIONE: Il file sarà sovrascritto se esistente.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d chiave segreta corrotta ignorata. Tra l\'altro hai esportato con l\'opzione\n --export-secret-subkeys\nAssicurati di esportare con\n --export-secret-keys\ninvece.</item>
<item quantity="other">%d chiavi segrete corrotte ignorate. Tra l\'altro hai esportato con l\'opzione\n --export-secret-subkeys\nAssicurati di esportare con\n --export-secret-keys\ninvece.</item>
@@ -207,32 +239,47 @@
<string name="nfc_successful">Chiave correttamente inviata tramite NFC Beam!</string>
<string name="key_copied_to_clipboard">Chiave copiata negli appunti!</string>
<string name="fingerprint_copied_to_clipboard">Impronta copiata negli appunti!</string>
+ <string name="select_key_to_certify">Per favore seleziona una chiave da utilizzare per la conferma!</string>
<string name="key_too_big_for_sharing">Chiave troppo grande per essere condivisa in questo modo!</string>
<string name="text_copied_to_clipboard">Il testo è stato copiato sulla lavagna!</string>
<!--errors
no punctuation, all lowercase,
they will be put after "error_message", e.g. "Error: file not found"-->
+ <string name="error_file_delete_failed">non sono stati cancellati. Cancellare manualmente!</string>
+ <string name="error_file_added_already">%s è già stato aggiunto.</string>
<string name="error_file_not_found">File non trovato</string>
<string name="error_no_secret_key_found">nessuna chiave privata adatta trovata</string>
<string name="error_external_storage_not_ready">memoria esterna non pronta</string>
<string name="error_key_size_minimum512bit">La grandezza della chiave deve essere almeno di 512bit</string>
<string name="error_unknown_algorithm_choice">opzione algoritmo sconosciuta</string>
+ <string name="error_user_id_no_email">nessun indirizzo di posta elettronica trovato</string>
<string name="error_key_needs_a_user_id">neccessaria almeno una identità</string>
+ <string name="error_no_signature_passphrase">nessuna password</string>
<string name="error_no_signature_key">nessuna chiave di firma inserita</string>
<string name="error_invalid_data">Contenuti OpenPGP firmati o codificati non validi!</string>
<string name="error_integrity_check_failed">Controllo di integrita\' fallito! I dati sono stati modificati!</string>
+ <string name="error_wrong_passphrase">Password errata</string>
<string name="error_could_not_extract_private_key">impossibile estrarre la chiave privata</string>
<!--errors without preceeding Error:-->
<string name="error_jelly_bean_needed">Devi avere Android 4.1 per usare Android NFC Beam!</string>
+ <string name="error_nfc_needed">NFC deve essere abilitato!</string>
<string name="error_nothing_import">Nessuna chiave trovata!</string>
+ <string name="error_nothing_import_selected">Nessune chiavi selezionate per l\'importazione!</string>
<string name="error_contacts_key_id_missing">Recupero dell\'ID della chiave dai contatti fallito!</string>
<string name="error_generic_report_bug">Si è verificato un errore generico, si prega di creare una nuova segnalazione di errore per OpenKeychain.</string>
<!--results shown after decryption/verification-->
<string name="decrypt_result_no_signature">Non Firmato</string>
<string name="decrypt_result_invalid_signature">Firma non valida!</string>
+ <string name="decrypt_result_signature_uncertified">Firmato da chiave <b> non confermata </b></string>
+ <string name="decrypt_result_signature_secret">Firmato con tua chiave</string>
+ <string name="decrypt_result_signature_certified">Firmato con chiave confermata</string>
+ <string name="decrypt_result_signature_expired_key">Firmato con chiave <b>scaduta</b>!</string>
+ <string name="decrypt_result_signature_revoked_key">Firmato con chiave <b>revocata</b>!</string>
+ <string name="decrypt_result_signature_missing_key">Firmato con chiave <b>pubblica sconusciuta</b></string>
<string name="decrypt_result_encrypted">Codificato</string>
<string name="decrypt_result_not_encrypted">Non Codificato</string>
<string name="decrypt_result_action_show">Mostra</string>
+ <string name="decrypt_invalid_button">Capisco i rischi, visualizza!</string>
<!--Add keys-->
<string name="add_keys_my_key">Mia chiave:</string>
<!--progress dialogs, usually ending in '…'-->
@@ -259,6 +306,7 @@
<string name="progress_modify_subkeyrevoke">Revoca sottochiave...</string>
<string name="progress_modify_subkeystrip">pulizia sottochiavi...</string>
<string name="progress_modify_subkeyadd">Aggiunta sottochiave...</string>
+ <string name="progress_modify_passphrase">cambiando la password...</string>
<plurals name="progress_exporting_key">
<item quantity="one">esportazione chiave...</item>
<item quantity="other">esportazione chiavi...</item>
@@ -310,6 +358,7 @@
<!--Help-->
<string name="help_tab_start">Inizia</string>
<string name="help_tab_faq">FAQ</string>
+ <string name="help_tab_wot">Conferma chiave</string>
<string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Novita\'</string>
<string name="help_tab_about">Info</string>
@@ -371,7 +420,7 @@
<string name="api_settings_start">Avvia applicazione</string>
<string name="api_settings_delete_account">Cancella account</string>
<string name="api_settings_package_name">Nome Pacchetto</string>
- <string name="api_settings_package_signature">SHA-256 della Firma del Pacchetto</string>
+ <string name="api_settings_package_certificate">SHA-256 della Firma del Pacchetto</string>
<string name="api_settings_settings">Impostazioni</string>
<string name="api_settings_key">Chiave account:</string>
<string name="api_settings_accounts_empty">Nessun account collegato a questa applicazione</string>
@@ -445,7 +494,7 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<string name="create_key_custom">(personalizza la configurazione della chiave)</string>
<string name="create_key_edit">Cambia configurazione della chiave</string>
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<string name="nav_keys">Chiavi</string>
<string name="nav_apps">Apps</string>
@@ -671,6 +720,7 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<item quantity="one">parte del file caricato e\' un oggetto OpenPGP valido, ma non una chave OpenPGP</item>
<item quantity="other">parti del file caricato sono oggetti OpenPGP validi, ma non chavi OpenPGP</item>
</plurals>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
@@ -693,7 +743,7 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<string name="unknown_algorithm">sconosciuto</string>
<string name="can_sign_not">non può firmare</string>
<string name="error_no_encrypt_subkey">Nessuna sottochiave di codifica disponibile!</string>
- <string name="info_no_manual_account_creation">Non creare account OpenKeychain manualmente.\nPer ulteriori informazioni, vedere la Guida.</string>
+ <string name="account_no_manual_account_creation">Non creare account OpenKeychain manualmente.\nPer ulteriori informazioni, vedere la Guida.</string>
<string name="contact_show_key">Mostra chiave (%s)</string>
<string name="error_no_file_selected">Seleziona almeno un file da codificare!</string>
<string name="key_colon">Chiave:</string>
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index 790913684..690fa0134 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -202,7 +202,7 @@
<string name="error_no_encryption_or_signature_key">少なくとも1つの暗号化鍵か署名鍵を選択して下さい。</string>
<string name="specify_file_to_encrypt_to">どれのファイルを暗号化するのを入力してください。\n注意:ファイルが存在しているなら上書きされる!</string>
<string name="specify_file_to_decrypt_to">どれのファイルを暗号するのを入力してください。\n注意:ファイルが存在しているなら上書きされる!</string>
- <string name="specify_file_to_export_to">どれのファイルを復号化するのを入力してください。\n注意:ファイルが存在しているなら上書きされる!</string>
+ <string name="specify_backup_dest">どれのファイルを復号化するのを入力してください。\n注意:ファイルが存在しているなら上書きされる!</string>
<string name="key_deletion_confirmation_multi">選択したすべての鍵を本当に削除してよいですか?</string>
<string name="secret_key_deletion_confirmation">削除後はこの鍵で暗号化されたメッセージが読めなくなります、またその鍵で行われたすべての鍵確認を失います!</string>
<string name="public_key_deletetion_confirmation">鍵 \'%s\' を削除しますか?</string>
@@ -433,7 +433,7 @@
<string name="api_settings_start">アプリケーションを開始</string>
<string name="api_settings_delete_account">アカウントを削除</string>
<string name="api_settings_package_name">パッケージ名</string>
- <string name="api_settings_package_signature">パッケージの署名 SHA-256</string>
+ <string name="api_settings_package_certificate">パッケージの署名 SHA-256</string>
<string name="api_settings_accounts">アカウント(deprecated API)</string>
<string name="api_settings_advanced">詳細情報</string>
<string name="api_settings_allowed_keys">受け入れる鍵</string>
@@ -1097,7 +1097,7 @@
<string name="unknown_algorithm">不明</string>
<string name="can_sign_not">署名不可</string>
<string name="error_no_encrypt_subkey">暗号化の副鍵がありません!</string>
- <string name="info_no_manual_account_creation">OpenKeychainのアカウントを手動では生成できません.
+ <string name="account_no_manual_account_creation">OpenKeychainのアカウントを手動では生成できません.
より詳細は、ヘルプを参照のこと。</string>
<string name="contact_show_key">鍵 (%s) を表示</string>
<string name="swipe_to_update">下スワイプでキーサーバから更新します</string>
diff --git a/OpenKeychain/src/main/res/values-kn/strings.xml b/OpenKeychain/src/main/res/values-kn/strings.xml
index 8f84af665..0713e39ad 100644
--- a/OpenKeychain/src/main/res/values-kn/strings.xml
+++ b/OpenKeychain/src/main/res/values-kn/strings.xml
@@ -7,6 +7,11 @@
<!--button-->
<!--menu-->
<!--label-->
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<!--choice-->
<!--key flags-->
<!--sentences-->
@@ -42,7 +47,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -61,6 +66,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml
index a9fbcae7f..cc00ebd63 100644
--- a/OpenKeychain/src/main/res/values-nl/strings.xml
+++ b/OpenKeychain/src/main/res/values-nl/strings.xml
@@ -43,6 +43,7 @@
<string name="section_keys">Subsleutels</string>
<string name="section_cloud_search">Cloud zoeken</string>
<string name="section_passphrase_cache">Verwerken van wachtwoorden/PINs</string>
+ <string name="section_proxy_settings">Proxy-instellingen</string>
<string name="section_certify">Bevestigen</string>
<string name="section_actions">Acties</string>
<string name="section_share_key">Sleutel</string>
@@ -56,6 +57,8 @@
<string name="btn_decrypt_verify_file">Ontsleutel, verifieer en sla bestand op</string>
<string name="btn_encrypt_share_file">Bestand versleutelen en delen</string>
<string name="btn_encrypt_save_file">Bestand versleutelen en opslaan</string>
+ <string name="btn_save_file">Bestand opslaan</string>
+ <string name="btn_save">Opslaa</string>
<string name="btn_view_log">Bekijk log</string>
<string name="btn_do_not_save">Annuleren</string>
<string name="btn_delete">Verwijderen</string>
@@ -98,6 +101,7 @@
<string name="menu_advanced">Uitgebreide informatie</string>
<string name="menu_certify_fingerprint">Bevestigen door vingerafdrukken te vergelijken</string>
<string name="menu_export_log">Log exporteren</string>
+ <string name="menu_keyserver_add">Toevoegen</string>
<!--label-->
<string name="label_message">Tekst</string>
<string name="label_file">Bestand</string>
@@ -116,7 +120,6 @@
<string name="label_use_default_yubikey_pin">Gebruik standaard YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Gebruik numeriek toetsenbord voor YubiKey PIN</string>
<string name="label_label_use_default_yubikey_pin_summary">Gebruikt standaard PIN (123456) om YubiKeys over NFC te bereiken</string>
- <string name="label_asymmetric_from">Ondertekend door:</string>
<string name="label_to">Versleutelen naar:</string>
<string name="label_delete_after_encryption">Verwijder bestanden na versleuteling</string>
<string name="label_delete_after_decryption">Verwijderen na ontsleuteling</string>
@@ -142,17 +145,49 @@
<string name="label_send_key">Synchroniseren met de cloud</string>
<string name="label_fingerprint">Vingerafdruk</string>
<string name="expiry_date_dialog_title">Bepaal verloopdatum</string>
- <string name="label_first_keyserver_is_used">(Voorkeur gaat uit naar de eerste keyserver in de lijst)</string>
+ <string name="label_keyservers_title">Sleutelservers</string>
+ <string name="label_keyserver_settings_hint">Sleep om de volgorde te wijzigen, tik om te bewerken/verwijderen</string>
+ <string name="label_selected_keyserver_title">Gekozen sleutelserver</string>
<string name="label_preferred">voorkeur</string>
<string name="label_enable_compression">Compressie aanzetten</string>
<string name="label_encrypt_filenames">Versleutel bestandsnamen</string>
<string name="label_hidden_recipients">Verberg ontvangers</string>
<string name="label_verify_keyserver">Sleutelserver verifiëren</string>
<string name="label_enter_keyserver_url">Voer sleutelserver-URL in</string>
+ <string name="label_keyserver_dialog_delete">Sleutelserver verwijderen</string>
<string name="pref_keyserver">OpenPGP-sleutelservers</string>
<string name="pref_keyserver_summary">Zoek sleutels op geselecteerde OpenPGP-sleutelservers (HKP-protocol)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Zoek sleutels op keybase.io</string>
+ <!--Proxy Preferences-->
+ <string name="pref_proxy_tor_title">Tor aanzetten</string>
+ <string name="pref_proxy_tor_summary">Vereist dat Orbot geïnstalleerd is</string>
+ <string name="pref_proxy_normal_title">Andere proxy aanzetten</string>
+ <string name="pref_proxy_host_title">Proxy-host</string>
+ <string name="pref_proxy_host_err_invalid">Proxy-host kan niet leeg zijn</string>
+ <string name="pref_proxy_port_title">Proxy-poort</string>
+ <string name="pref_proxy_port_err_invalid">Ongeldig poortnummer opgegeven</string>
+ <string name="pref_proxy_type_title">Proxy-type</string>
+ <!--proxy type choices and values-->
+ <string name="pref_proxy_type_choice_http">HTTP</string>
+ <string name="pref_proxy_type_choice_socks">SOCKS</string>
+ <string name="pref_proxy_type_value_http">proxyHttp</string>
+ <string name="pref_proxy_type_value_socks">proxySocks</string>
+ <!--OrbotHelper strings-->
+ <string name="orbot_ignore_tor">Gebruik Tor niet</string>
+ <!--InstallDialogFragment strings-->
+ <string name="orbot_install_dialog_title">Orbot installeren om Tor te gebruiken?</string>
+ <string name="orbot_install_dialog_install">Installeren</string>
+ <string name="orbot_install_dialog_content">Orbot moet geïnstalleerd en ingesteld zijn om verkeer erdoor te proxyen. Wil je het installeren?</string>
+ <string name="orbot_install_dialog_cancel">Annuleren?</string>
+ <string name="orbot_install_dialog_ignore_tor">Gebruik Tor niet</string>
+ <!--StartOrbotDialogFragment strings-->
+ <string name="orbot_start_dialog_title">Orbot starten?</string>
+ <string name="orbot_start_dialog_content">Orbot wordt niet uitgevoerd. Wil je het opstarten en verbinden met Tor?</string>
+ <string name="orbot_start_btn">Orbot starten</string>
+ <string name="orbot_start_dialog_start">Orbot starten</string>
+ <string name="orbot_start_dialog_cancel">Annuleren</string>
+ <string name="orbot_start_dialog_ignore_tor">Gebruik Tor niet</string>
<string name="user_id_no_name">&lt;no naam&gt;</string>
<string name="none">&lt;geen&gt;</string>
<plurals name="n_keys">
@@ -200,7 +235,8 @@
<string name="passphrase_for">Voer het wachtwoord in voor \'%s\'</string>
<string name="pin_for">Voer PIN in voor \'%s\'</string>
<string name="yubikey_pin_for">Voer PIN in om toegang te verkrijgen tot YubiKey voor \'%s\'</string>
- <string name="nfc_text">Hou YubiKey tegen de achterkant van je toestel</string>
+ <string name="nfc_text">Hou de YubiKey tegen de NFC-aanduiding aan de achterkant van je toestel.</string>
+ <string name="nfc_wait">Hou de YubiKey tegen de achterkant!</string>
<string name="file_delete_confirmation_title">Oorspronkelijke bestanden verwijderen?</string>
<string name="file_delete_confirmation">De volgende bestanden zullen worden verwijderd:%s</string>
<string name="file_delete_successful">%1$d van %2$d bestanden zijn verwijderd.%3$s</string>
@@ -211,7 +247,7 @@
<string name="error_no_encryption_or_signature_key">Kies ten minste één versleutelingssleutel of een ondertekeningssleutel.</string>
<string name="specify_file_to_encrypt_to">Gelieve aan te geven naar welk bestand versleuteld moet worden.\nWAARSCHUWING: Als het bestand al bestaat, zal het overschreven worden!</string>
<string name="specify_file_to_decrypt_to">Gelieve aan te geven naar welk bestand ontsleuteld moet worden.\nWAARSCHUWING: Als het bestand al bestaat, zal het overschreven worden!</string>
- <string name="specify_file_to_export_to">Gelieve aan te geven naar welk bestand geëxporteerd moet worden.\nWAARSCHUWING: Als het bestand al bestaat, zal het overschreven worden!</string>
+ <string name="specify_backup_dest">Gelieve aan te geven naar welk bestand geëxporteerd moet worden.\nWAARSCHUWING: Als het bestand al bestaat, zal het overschreven worden!</string>
<string name="key_deletion_confirmation_multi">Ben je zeker dat je alle geselecteerde sleutels wil verwijderen?</string>
<string name="secret_key_deletion_confirmation">Na verwijderen zal je niet langer berichten versleuteld met deze sleutel kunnen lezen, en alle sleutelbevestigingen die ermee gedaan zijn verliezen!</string>
<string name="public_key_deletetion_confirmation">Sleutel \'%s\' verwijderen?</string>
@@ -304,6 +340,8 @@
<string name="progress_modify_subkeystrip">bezig met strippen van subsleutels…</string>
<string name="progress_modify_subkeyadd">bezig met toevoegen van subsleutels…</string>
<string name="progress_modify_passphrase">bezig met veranderen van wachtwoord…</string>
+ <string name="progress_modify_pin">bezig met veranderen van PIN…</string>
+ <string name="progress_modify_admin_pin">bezig met veranderen van administrator-PIN…</string>
<plurals name="progress_exporting_key">
<item quantity="one">sleutel exporteren…</item>
<item quantity="other">sleutels exporteren…</item>
@@ -459,7 +497,7 @@
<string name="api_settings_start">Start applicatie</string>
<string name="api_settings_delete_account">Verwijder account</string>
<string name="api_settings_package_name">Pakketnaam</string>
- <string name="api_settings_package_signature">SHA-256 van Pakkethandtekening</string>
+ <string name="api_settings_package_certificate">SHA-256 van Pakkethandtekening</string>
<string name="api_settings_accounts">Accounts (oude API)</string>
<string name="api_settings_advanced">Uitgebreide informatie</string>
<string name="api_settings_allowed_keys">Toegestane sleutels</string>
@@ -596,6 +634,13 @@
<string name="create_key_add_email_text">Bijkomstige e-mailadressen zijn ook verbonden met deze sleutel en kunnen gebruikt worden voor veilige communicatie.</string>
<string name="create_key_email_already_exists_text">E-mailadres is al toegevoegd</string>
<string name="create_key_email_invalid_email">E-mailadresformaat is ongeldig</string>
+ <string name="create_key_yubi_key_pin_text">Onthou deze PIN, ze is nodig om je YubiKey later te gebruiken. Schrijf indien mogelijk de administrator-PIN ergens op en bewaar deze op een veilige plek.</string>
+ <string name="create_key_yubi_key_pin">PIN</string>
+ <string name="create_key_yubi_key_admin_pin">Administrator-PIN</string>
+ <string name="create_key_yubi_key_pin_repeat_text">Voer de PIN en administrator-PIN in om door te gaan.</string>
+ <string name="create_key_yubi_key_pin_repeat">Herhaal PIN</string>
+ <string name="create_key_yubi_key_admin_pin_repeat">Herhaal administrator-PIN</string>
+ <string name="create_key_yubi_key_pin_not_correct">PIN is niet correct!</string>
<!--View key-->
<string name="view_key_revoked">Ingetrokken: sleutel mag niet meer gebruikt worden!</string>
<string name="view_key_expired">Verlopen: het contact moet de geldigheid van de sleutel verlengen!</string>
@@ -604,12 +649,15 @@
<string name="view_key_verified">Bevestigde sleutel</string>
<string name="view_key_unverified">Niet bevestigd: scan QR-code om de sleutel te bevestigen!</string>
<string name="view_key_fragment_no_system_contact">&lt;geen&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Sleutelserver toevoegen</string>
+ <string name="edit_keyserver_dialog_title">Sleutelserver bewerken</string>
<string name="add_keyserver_verified">Sleutelserver geverifieerd!</string>
<string name="add_keyserver_without_verification">Sleutelserver toegevoegd zonder verificatie.</string>
<string name="add_keyserver_invalid_url">Ongeldige URL!</string>
<string name="add_keyserver_connection_failed">Kon niet verbinden met sleutelserver. Controleer de URL en je internetverbinding.</string>
+ <string name="keyserver_preference_deleted">%s verwijderd</string>
+ <string name="keyserver_preference_cannot_delete_last">Kan laatste sleutelserver niet verwijderen, er is er minstens één nodig!</string>
<!--Navigation Drawer-->
<string name="nav_keys">Sleutels</string>
<string name="nav_encrypt_decrypt">Versleutelen/Ontsleutelen</string>
@@ -868,6 +916,8 @@
<string name="msg_mf_notation_empty">Bezig met toevoegen van leeg notatiepakket</string>
<string name="msg_mf_notation_pin">Bezig met toevoegen van PIN-notatiepakket</string>
<string name="msg_mf_passphrase">Bezig met wijzigen van wachtwoord voor sleutelbos</string>
+ <string name="msg_mf_pin">Bezig met veranderen van PIN op kaart</string>
+ <string name="msg_mf_admin_pin">Bezig met veranderen van administrator-PIN op kaart</string>
<string name="msg_mf_passphrase_key">Bezig met opnieuw versleutelen van subsleutel %s met nieuw wachtwoord</string>
<string name="msg_mf_passphrase_empty_retry">Instellen van nieuw wachtwoord mislukt, opnieuw proberen met leeg oud wachtwoord</string>
<string name="msg_mf_passphrase_fail">Wachtwoord voor subsleutel kon niet gewijzigd worden! (Heeft het een ander wachtwoord dan de andere sleutels?)</string>
@@ -968,7 +1018,6 @@
<string name="msg_dc_error_integrity_check">Fout bij integriteitscontrole!</string>
<string name="msg_dc_error_integrity_missing">Integriteitscheck ontbreekt! Dit kan gebeuren omdat de versleutelingsapplicatie verouderd is, of door een downgrade-aanval.</string>
<string name="msg_dc_error_invalid_data">Geen geldige OpenPGP-versleutelde of ondertekende inhoud gevonden!</string>
- <string name="msg_dc_error_io">I/O-uitzondering tegengekomen tijdens bewerking!</string>
<string name="msg_dc_error_no_data">Geen versleutelde gegevens gevonden!</string>
<string name="msg_dc_error_no_key">Geen versleutelde gegevens met bekende geheime sleutel gevonden!</string>
<string name="msg_dc_error_pgp_exception">OpenPGP-uitzondering tegengekomen tijdens bewerking!</string>
@@ -1058,6 +1107,7 @@
<string name="msg_crt_warn_not_found">Sleutel niet gevonden!</string>
<string name="msg_crt_warn_cert_failed">Aanmaken van certificaat mislukt!</string>
<string name="msg_crt_warn_save_failed">Opslaan mislukt!</string>
+ <string name="msg_crt_warn_upload_failed">Uploaden mislukt!</string>
<string name="msg_crt_upload_success">Sleutel succesvol geüpload naar server</string>
<plurals name="msg_import">
<item quantity="one">Bezig met importeren van sleutel</item>
@@ -1084,6 +1134,7 @@
</plurals>
<string name="msg_export_all">Bezig met exporteren van alle sleutels</string>
<string name="msg_export_public">Bezig met exporteren van publieke sleutel %s</string>
+ <string name="msg_export_upload_public">Bezig met uploaden van publieke sleutel %s</string>
<string name="msg_export_secret">Bezig met exporteren van geheime sleutel %s</string>
<string name="msg_export_error_no_file">Geen bestandsnaam opgegeven!</string>
<string name="msg_export_error_fopen">Fout bij openen van bestand!</string>
@@ -1093,7 +1144,9 @@
<string name="msg_export_error_db">Databasefout!</string>
<string name="msg_export_error_io">Input/output-fout!</string>
<string name="msg_export_error_key">Fout bij voorwerken van sleutelgegevens!</string>
+ <string name="msg_export_error_upload">Fout bij uploaden van sleutel naar server! Controleer je internetverbinding</string>
<string name="msg_export_success">Exporteren geslaagd</string>
+ <string name="msg_export_upload_success">Uploaden naar sleutelserver geslaagd</string>
<string name="msg_del_error_empty">Niets om te verwijderen!</string>
<string name="msg_del_error_multi_secret">Geheime sleutels kunnen enkel individueel verwijderd worden!</string>
<plurals name="msg_del">
@@ -1123,6 +1176,14 @@
<string name="msg_download_too_many_responses">Zoekopdracht gaf te veel kandidaten. Gelieve je zoekopdracht te verfijnen!</string>
<string name="msg_download_query_too_short_or_too_many_responses">Geen of te veel sleutels werden gevonden. Gelieve je zoekopdracht te verfijnen!</string>
<string name="msg_download_query_failed">Er trad een fout op bij het zoeken naar sleutels.</string>
+ <!--Messages for Keybase Verification operation-->
+ <string name="msg_keybase_verification">Keybaseverificatie voor %s wordt geprobeerd</string>
+ <string name="msg_keybase_error_no_prover">Geen bewijschecker gevonden voor %s</string>
+ <string name="msg_keybase_error_fetching_evidence">Probleem bij ophalen van bewijs</string>
+ <string name="msg_keybase_error_key_mismatch">Sleutelvingerafdruk komt niet overeen met die in bewijspost</string>
+ <string name="msg_keybase_error_dns_fail">DNS TXT record ophalen mislukt</string>
+ <string name="msg_keybase_error_specific">%s</string>
+ <string name="msg_keybase_error_msg_payload_mismatch">Ontsleuteld bewijs komt niet overeen met verwachte waarde</string>
<!--Messages for Export Log operation-->
<string name="msg_export_log_start">Bezig met exporteren van log</string>
<string name="msg_export_log_error_fopen">Fout bij openen van bestand</string>
@@ -1144,6 +1205,8 @@
<string name="first_time_import_key">Sleutel importeren uit bestand</string>
<string name="first_time_yubikey">Gebruik YubiKey NEO</string>
<string name="first_time_skip">Setup overslaan</string>
+ <string name="first_time_blank_yubikey">Wil je deze lege YubiKey NEO gebruiken met OpenKeychain?\n\nNeem de YubiKey nu weg, je zal gevraagd worden deze terug boven te halen wanneer nodig!</string>
+ <string name="first_time_blank_yubikey_yes">Gebruik deze YubiKey</string>
<!--unsorted-->
<string name="section_certifier_id">Certificeer</string>
<string name="section_cert">Certificaat Details</string>
@@ -1168,7 +1231,7 @@
<string name="unknown_algorithm">onbekend</string>
<string name="can_sign_not">kan niet ondertekenen</string>
<string name="error_no_encrypt_subkey">Geen codeer-subsleutel beschikbaar!</string>
- <string name="info_no_manual_account_creation">Maak OpenKeychain-accounts niet handmatig aan.\nVoor meer informatie, zie Help.</string>
+ <string name="account_no_manual_account_creation">Maak OpenKeychain-accounts niet handmatig aan.\nVoor meer informatie, zie Help.</string>
<string name="contact_show_key">Toon sleutel (%s)</string>
<string name="swipe_to_update">Veeg naar beneden om van sleutelserver te updaten</string>
<string name="error_no_file_selected">Selecteer minstens een bestand om te versleutelen!</string>
@@ -1219,18 +1282,8 @@
<string name="btn_import">Importeren</string>
<string name="snack_yubi_other">Andere sleutel opgeslagen op YubiKey!</string>
<string name="error_nfc">NFC-fout: %s</string>
- <string name="error_pin">NFC: ongeldige PIN; %d resterende pogingen.</string>
- <string name="error_nfc_terminated">NFC: smartcard in beëindigingsstaat</string>
- <string name="error_nfc_wrong_length">NFC: verkeerde lengte voor verzonden / ontvangen gegevens</string>
- <string name="error_nfc_conditions_not_satisfied">NFC: gebruiksvoorwaarden niet voldaan</string>
- <string name="error_nfc_security_not_satisfied">NFC: veiligheidsstatus niet voldaan</string>
- <string name="error_nfc_authentication_blocked">NFC: PIN geblokkeerd na te veel pogingen</string>
- <string name="error_nfc_data_not_found">NFC: sleutel of object niet gevonden</string>
- <string name="error_nfc_unknown">NFC: onbekende fout</string>
- <string name="error_nfc_bad_data">NFC: kaart gaf ongeldige gegevens weer</string>
- <string name="error_nfc_chaining_error">NFC: kaart verwachtte laatste commando in een reeks</string>
- <string name="error_nfc_header">NFC: kaart gaf ongeldige %s byte weer</string>
<string name="error_pin_nodefault">Standaard-PIN geweigerd!</string>
+ <string name="error_temp_file">Fout bij aanmaken van tijdelijk bestand.</string>
<string name="btn_delete_original">Oorspronkelijk bestand verwijderen</string>
<string name="snack_encrypt_filenames_on">Bestandsnamen <b>zijn</b> versleuteld.</string>
<string name="snack_encrypt_filenames_off">Bestandsnamen <b>zijn niet</b> versleuteld.</string>
@@ -1253,4 +1306,5 @@
<string name="file_delete_ok">Oorspronkelijk bestand verwijderd.</string>
<string name="file_delete_none">Geen bestand verwijderd! (Misschien was het al verwijderd?)</string>
<string name="file_delete_exception">Oorspronkelijk bestand kon niet worden verwijderd!</string>
+ <string name="error_clipboard_empty">Klembord is leeg!</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-pl/strings.xml b/OpenKeychain/src/main/res/values-pl/strings.xml
index 1cf1c9958..db15b3e67 100644
--- a/OpenKeychain/src/main/res/values-pl/strings.xml
+++ b/OpenKeychain/src/main/res/values-pl/strings.xml
@@ -77,7 +77,6 @@
<string name="label_use_default_yubikey_pin">Użyj domyślnego PIN-u YubiKey</string>
<string name="label_use_num_keypad_for_yubikey_pin">Użyj klawiatury numerycznej dla PIN-u YubiKey</string>
<string name="label_label_use_default_yubikey_pin_summary">Używa domyślnego PIN-u (123456) do dostępu do YubiKeys przez NFC</string>
- <string name="label_asymmetric_from">Podpisane przez:</string>
<string name="label_to">Szyfruj do:</string>
<string name="label_delete_after_decryption">Usuń po odszyfrowaniu</string>
<string name="label_encryption_algorithm">Algorytm szyfrowania</string>
@@ -96,8 +95,12 @@
<string name="label_send_key">Synchronizuj z chmurą</string>
<string name="label_fingerprint">Odcisk</string>
<string name="expiry_date_dialog_title">Ustaw datę wygaśnięcia</string>
- <string name="label_first_keyserver_is_used">(Pierwszy serwer kluczy jest preferowany)</string>
<string name="label_preferred">preferowany</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;bez nazwy&gt;</string>
<string name="none">&lt;żaden&gt;</string>
<plurals name="n_keys">
@@ -142,7 +145,6 @@
<string name="no_filemanager_installed">Nie zainstalowano żadnego kompatybilnego menadżera plików.</string>
<string name="passphrase_for_symmetric_encryption">Szyfrowanie symetryczne.</string>
<string name="pin_for">Wpisz PIN dla \'%s\'</string>
- <string name="nfc_text">Trzymaj YubiKey z tyłu Twojego urządzenia.</string>
<string name="encrypt_sign_successful">Pomyślnie podpisano i/lub zaszyfrowano.</string>
<string name="encrypt_sign_clipboard_successful">Pomyslnie podpisano i/lub zaszyfrowano do schowka.</string>
<string name="select_encryption_key">Wybierz co najmniej jeden klucz szyfrujący.</string>
@@ -370,7 +372,7 @@
<string name="api_settings_start">Uruchom aplikację</string>
<string name="api_settings_delete_account">Usuń konto</string>
<string name="api_settings_package_name">Nazwa paczki</string>
- <string name="api_settings_package_signature">Skrót SHA-256 podpisu paczki</string>
+ <string name="api_settings_package_certificate">Skrót SHA-256 podpisu paczki</string>
<string name="api_settings_settings">Ustawienia</string>
<string name="api_settings_key">Klucz konta:</string>
<string name="api_settings_accounts_empty">Brak kont połączonych z tą aplikacją.</string>
@@ -451,7 +453,7 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<string name="create_key_hint_full_name">Pełne imię lub przezwisko</string>
<string name="create_key_edit">Zmień ustawienia klucza</string>
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<string name="nav_keys">Klucze</string>
<string name="nav_encrypt_decrypt">Zaszyfruj/Odszyfruj</string>
@@ -560,6 +562,7 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<item quantity="few">Część wczytanego pliku to poprawne obiekty OpenPGP, ale nie są kluczami OpenPGP</item>
<item quantity="other">Część wczytanego pliku to poprawne obiekty OpenPGP, ale nie są kluczami OpenPGP</item>
</plurals>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-pt/strings.xml b/OpenKeychain/src/main/res/values-pt/strings.xml
index 8f84af665..0713e39ad 100644
--- a/OpenKeychain/src/main/res/values-pt/strings.xml
+++ b/OpenKeychain/src/main/res/values-pt/strings.xml
@@ -7,6 +7,11 @@
<!--button-->
<!--menu-->
<!--label-->
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<!--choice-->
<!--key flags-->
<!--sentences-->
@@ -42,7 +47,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -61,6 +66,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-ro/strings.xml b/OpenKeychain/src/main/res/values-ro/strings.xml
index 8f84af665..0713e39ad 100644
--- a/OpenKeychain/src/main/res/values-ro/strings.xml
+++ b/OpenKeychain/src/main/res/values-ro/strings.xml
@@ -7,6 +7,11 @@
<!--button-->
<!--menu-->
<!--label-->
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<!--choice-->
<!--key flags-->
<!--sentences-->
@@ -42,7 +47,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -61,6 +66,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index e5e164c49..c13796795 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -367,7 +367,7 @@
<string name="api_settings_start">Запустить приложение</string>
<string name="api_settings_delete_account">Удалить аккаунт</string>
<string name="api_settings_package_name">Наименование пакета</string>
- <string name="api_settings_package_signature">SHA-256 подписи пакета</string>
+ <string name="api_settings_package_certificate">SHA-256 подписи пакета</string>
<string name="api_settings_accounts">Аккаунты (устаревший API)</string>
<string name="api_settings_advanced">Подробная информация</string>
<string name="api_settings_allowed_keys">Разрешённые ключи</string>
diff --git a/OpenKeychain/src/main/res/values-sl/strings.xml b/OpenKeychain/src/main/res/values-sl/strings.xml
index 4498cccb3..ab3f009df 100644
--- a/OpenKeychain/src/main/res/values-sl/strings.xml
+++ b/OpenKeychain/src/main/res/values-sl/strings.xml
@@ -96,7 +96,6 @@
<string name="label_use_default_yubikey_pin">Uporabi privzeto YubiKey PIN kodo</string>
<string name="label_use_num_keypad_for_yubikey_pin">Uporabi numerično tipkovnico za YubiKey PIN kodo</string>
<string name="label_label_use_default_yubikey_pin_summary">Uporablja privzeto PIN kodo (123456) za dostop do ključev YubiKey preko NFC</string>
- <string name="label_asymmetric_from">Podpisal:</string>
<string name="label_to">Šifriraj za:</string>
<string name="label_delete_after_encryption">Po dešifriranju izbriši datoteke</string>
<string name="label_delete_after_decryption">Izbriši po dešifriranju</string>
@@ -117,11 +116,15 @@
<string name="label_send_key">Sinhroniziraj z oblakom</string>
<string name="label_fingerprint">Prstni odtis</string>
<string name="expiry_date_dialog_title">Določi datum poteka veljavnosti</string>
- <string name="label_first_keyserver_is_used">(Prednost ima prvi strežnik na seznamu)</string>
<string name="label_preferred">prednostni</string>
<string name="label_enable_compression">Omogoči kompresijo</string>
<string name="label_encrypt_filenames">Šifriraj imena datotek</string>
<string name="label_hidden_recipients">Skrij prejemnike</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;brez imena&gt;</string>
<string name="none">&lt;nič&gt;</string>
<plurals name="n_keys">
@@ -169,7 +172,6 @@
<string name="passphrase_for_symmetric_encryption">Simetrično šifriranje.</string>
<string name="pin_for">Vnesite PIN kodo za \'%s\'</string>
<string name="yubikey_pin_for">Vnesite PIN kodo za dostop YubiKey za \'%s\'</string>
- <string name="nfc_text">Prislonite YubiKey k hrbtišču mobilne naprave.</string>
<string name="file_delete_confirmation_title">Izbrišem izvirne datoteke?</string>
<string name="file_delete_confirmation">Izbrisane bodo naslednje datoteke:%s</string>
<string name="file_delete_successful">Izbrisanih je bilo %1$d od %2$d datotek.%3$s</string>
@@ -178,7 +180,7 @@
<string name="select_encryption_key">Izberite vsaj en šifrirni ključ.</string>
<string name="specify_file_to_encrypt_to">Določite datoteko, v katero želite šifrirati vsebino.\nPOZOR: če datoteka že obstaja, bo prepisana.</string>
<string name="specify_file_to_decrypt_to">Določite datoteko, v katero želite dešifrirati vsebino.\nPOZOR: če datoteka že obstaja, bo prepisana.</string>
- <string name="specify_file_to_export_to">Določite datoteko, v katero želite izvoziti vsebino.\nPOZOR: če datoteka že obstaja, bo prepisana.</string>
+ <string name="specify_backup_dest">Določite datoteko, v katero želite izvoziti vsebino.\nPOZOR: če datoteka že obstaja, bo prepisana.</string>
<string name="key_deletion_confirmation_multi">Ali zares želite izbrisati vse izbrane ključe?</string>
<string name="secret_key_deletion_confirmation">Po izbrisu ne bo več mogoče prebirati sporočil šifriranih s tem ključem! Izgubljene bodo tudi vse z njim narejene potrditve.</string>
<string name="public_key_deletetion_confirmation">Izbrišem ključ \'%s\'?</string>
@@ -434,7 +436,7 @@
<string name="api_settings_start">Zaženi aplikacijo</string>
<string name="api_settings_delete_account">Izbriši račun</string>
<string name="api_settings_package_name">Ime paketa</string>
- <string name="api_settings_package_signature">SHA-256 podpisa paketa</string>
+ <string name="api_settings_package_certificate">SHA-256 podpisa paketa</string>
<string name="api_settings_allowed_keys">Dovoljeni ključi</string>
<string name="api_settings_settings">Nastavitve</string>
<string name="api_settings_key">Ključ računa:</string>
@@ -560,7 +562,7 @@
<string name="view_key_verified">Potrjen ključ</string>
<string name="view_key_unverified">Ključ ni potrjen: za potrditev skenirajte kodo QR!</string>
<string name="view_key_fragment_no_system_contact">&lt;brez&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<string name="nav_keys">Ključi</string>
<string name="nav_encrypt_decrypt">Šifriraj/Dešifriraj</string>
@@ -813,6 +815,7 @@
<item quantity="few">Deli naložene datoteke so veljavni objekti OpenPGP a niso ključi.</item>
<item quantity="other">Deli naložene datoteke so veljavni objekti OpenPGP a niso ključi.</item>
</plurals>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-sr/strings.xml b/OpenKeychain/src/main/res/values-sr/strings.xml
index ebacebb5f..ed385c9c2 100644
--- a/OpenKeychain/src/main/res/values-sr/strings.xml
+++ b/OpenKeychain/src/main/res/values-sr/strings.xml
@@ -212,7 +212,7 @@
<string name="error_no_encryption_or_signature_key">Изаберите бар један кључ за шифровање или потписивање.</string>
<string name="specify_file_to_encrypt_to">Одредите у који фајл да шифрујем.\nУПОЗОРЕЊЕ: Фајл ће бити пребрисан ако постоји.</string>
<string name="specify_file_to_decrypt_to">Одредите у који фајл да дешифрујем.\nУПОЗОРЕЊЕ: Фајл ће бити пребрисан ако постоји.</string>
- <string name="specify_file_to_export_to">Одредите у који фајл да извезем.\nУПОЗОРЕЊЕ: Фајл ће бити пребрисан ако постоји.</string>
+ <string name="specify_backup_dest">Одредите у који фајл да извезем.\nУПОЗОРЕЊЕ: Фајл ће бити пребрисан ако постоји.</string>
<string name="key_deletion_confirmation_multi">Желите ли заиста да обришете све изабране јавне кључеве?\nОво не можете да поништите!</string>
<string name="secret_key_deletion_confirmation">Желите ли заиста да обришете ТАЈНИ кључ „%s“?\nОво не можете да поништите!</string>
<string name="public_key_deletetion_confirmation">Желите ли заиста да обришете јавни кључ „%s“??\nОво не можете да поништите!</string>
@@ -465,7 +465,7 @@
<string name="api_settings_start">Покрени апликацију</string>
<string name="api_settings_delete_account">Обриши налог</string>
<string name="api_settings_package_name">Име пакета</string>
- <string name="api_settings_package_signature">СХА-256 потписа пакета</string>
+ <string name="api_settings_package_certificate">СХА-256 потписа пакета</string>
<string name="api_settings_accounts">Налози (застарели АПИ)</string>
<string name="api_settings_advanced">Напредни подаци</string>
<string name="api_settings_allowed_keys">Дозвољени кључеви</string>
@@ -1108,7 +1108,7 @@
<string name="unknown_algorithm">непознат</string>
<string name="can_sign_not">не може да потпише</string>
<string name="error_no_encrypt_subkey">Поткључ за шифровање није доступан!</string>
- <string name="info_no_manual_account_creation">Не прави налоге Отвореног кључарника ручно.\nПогледајте Помоћ за више информација.</string>
+ <string name="account_no_manual_account_creation">Не прави налоге Отвореног кључарника ручно.\nПогледајте Помоћ за више информација.</string>
<string name="contact_show_key">Прикажи кључ (%s)</string>
<string name="swipe_to_update">Превуците прстом доле да ажурирате са сервера кључева</string>
<string name="error_no_file_selected">Изаберите бар један фајл за шифровање!</string>
diff --git a/OpenKeychain/src/main/res/values-sv/strings.xml b/OpenKeychain/src/main/res/values-sv/strings.xml
index 8c9735d8f..0d9d4e205 100644
--- a/OpenKeychain/src/main/res/values-sv/strings.xml
+++ b/OpenKeychain/src/main/res/values-sv/strings.xml
@@ -111,7 +111,6 @@
<string name="label_use_default_yubikey_pin">Använd förvald YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Använd numeriska tangentbordet för YubiKey PIN</string>
<string name="label_label_use_default_yubikey_pin_summary">Använder förvald PIN (123456) för att få åtkomst till YubiKeys via NFC</string>
- <string name="label_asymmetric_from">Signerat av:</string>
<string name="label_to">Kryptera till:</string>
<string name="label_delete_after_encryption">Radera filer efter kryptering</string>
<string name="label_delete_after_decryption">Radera efter dekryptering</string>
@@ -135,7 +134,6 @@
<string name="label_send_key">Synkronisera med molnet</string>
<string name="label_fingerprint">Fingeravtryck</string>
<string name="expiry_date_dialog_title">Ställ in utgångsdatum</string>
- <string name="label_first_keyserver_is_used">(Nyckelservern först i listan är den som föredras)</string>
<string name="label_preferred">föredraget</string>
<string name="label_enable_compression">Aktivera kompression</string>
<string name="label_encrypt_filenames">Kryptera filnamn</string>
@@ -146,6 +144,11 @@
<string name="pref_keyserver_summary">Sök nycklar på valda OpenPGP nyckelservrar (HKP-protokollet)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Sök nycklar på keybase.io</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;inget namn&gt;</string>
<string name="none">&lt;ingen&gt;</string>
<plurals name="n_keys">
@@ -193,7 +196,6 @@
<string name="passphrase_for">Ange lösenord för \'%s\'</string>
<string name="pin_for">Ange PIN för \'%s\'</string>
<string name="yubikey_pin_for">Ange PIN för att få åtkomst till YubiKey för \'%s\'</string>
- <string name="nfc_text">Håll YubiKey mot baksidan av din enhet.</string>
<string name="file_delete_confirmation_title">Radera orginalfiler?</string>
<string name="file_delete_confirmation">Följande filer kommer raderas:%s</string>
<string name="file_delete_successful">%1$d av %2$d filer har raderats.%3$s</string>
@@ -202,7 +204,7 @@
<string name="select_encryption_key">Välj åtminstone en krypteringsnyckel.</string>
<string name="specify_file_to_encrypt_to">Ange vilken fil du vill kryptera till.\nVARNING: Om filen redan finns kommer den att skrivas över!</string>
<string name="specify_file_to_decrypt_to">Ange vilken fil du vill kryptera till.\nVARNING: Om filen redan finns kommer den att skrivas över!</string>
- <string name="specify_file_to_export_to">Ange vilken fil du vill exportera till.\nVARNING: Om filen redan finns kommer den att skrivas över!</string>
+ <string name="specify_backup_dest">Ange vilken fil du vill exportera till.\nVARNING: Om filen redan finns kommer den att skrivas över!</string>
<string name="key_deletion_confirmation_multi">Vill du verkligen radera alla markerade nycklar?</string>
<string name="secret_key_deletion_confirmation">Efter radering kommer du inte kunna läsa meddelande krypterade med den här nyckeln samt förlora alla nyckelbekräftningar som gjorts med den!</string>
<string name="public_key_deletetion_confirmation">Radera nyckel \'%s\'?</string>
@@ -442,7 +444,7 @@
<string name="api_settings_start">Starta app</string>
<string name="api_settings_delete_account">Radera konto</string>
<string name="api_settings_package_name">Paketnamn</string>
- <string name="api_settings_package_signature">SHA-256 för paketsignatur</string>
+ <string name="api_settings_package_certificate">SHA-256 för paketsignatur</string>
<string name="api_settings_accounts">Konton (gamla API:t)</string>
<string name="api_settings_advanced">Utökad information</string>
<string name="api_settings_allowed_keys">Tillåtna nycklar</string>
@@ -570,7 +572,7 @@
<string name="view_key_verified">Bekräftad nyckel</string>
<string name="view_key_unverified">Obekräftad: Skanna QR-kod för att bekräfta nyckeln!</string>
<string name="view_key_fragment_no_system_contact">&lt;ingen&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Lägg till nyckelserver</string>
<string name="add_keyserver_verified">Nyckelserver verifierad!</string>
<string name="add_keyserver_without_verification">Nyckelserver tillagd utan verifiering.</string>
@@ -879,6 +881,7 @@
<item quantity="one">en del av den inlästa filen är ett giltigt OpenPGP-objekt men inte en OpenPGP-nyckel</item>
<item quantity="other">delar av den inlästa filen är giltiga OpenPGP-objekt men inte OpenPGP-nycklar</item>
</plurals>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
@@ -904,7 +907,7 @@
<string name="unknown_algorithm">okänd</string>
<string name="can_sign_not">kan inte signera</string>
<string name="error_no_encrypt_subkey">Ingen krypteringsundernyckel tillgänglig!</string>
- <string name="info_no_manual_account_creation">Skapa inte OpenKeychain-konton manuellt. \nFör mer information, se Hjälp.</string>
+ <string name="account_no_manual_account_creation">Skapa inte OpenKeychain-konton manuellt. \nFör mer information, se Hjälp.</string>
<string name="contact_show_key">Visa nyckel (%s)</string>
<string name="swipe_to_update">Dra nedåt för att uppdatera från nyckelserver</string>
<string name="error_no_file_selected">Välj åtminstone en fil att kryptera!</string>
diff --git a/OpenKeychain/src/main/res/values-tr/strings.xml b/OpenKeychain/src/main/res/values-tr/strings.xml
index 77c5e1118..529e80aa7 100644
--- a/OpenKeychain/src/main/res/values-tr/strings.xml
+++ b/OpenKeychain/src/main/res/values-tr/strings.xml
@@ -66,7 +66,6 @@
<string name="label_use_default_yubikey_pin">Varsayılan YubiKey PIN\'ini kullan</string>
<string name="label_use_num_keypad_for_yubikey_pin">YubiKey PIN\'i için sayısal klavyeyi kullan</string>
<string name="label_label_use_default_yubikey_pin_summary">NFC üzerinden YubiKey\'e ulaşmak için varsayılan PIN\'i (123456) kullanır</string>
- <string name="label_asymmetric_from">İmzalayan:</string>
<string name="label_to">Şuna şifrele:</string>
<string name="label_delete_after_decryption">Şifre çözme sonrasında sil</string>
<string name="label_encryption_algorithm">Şifreleme algoritması</string>
@@ -85,8 +84,12 @@
<string name="label_send_key">Bulut ile eşitle</string>
<string name="label_fingerprint">Parmak izi</string>
<string name="expiry_date_dialog_title">Zaman aşımı tarihini ayarla</string>
- <string name="label_first_keyserver_is_used">(Listelenen ilk anahtar sunucu tercih edilecektir)</string>
<string name="label_preferred">tercih edilen</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;isimsiz&gt;</string>
<string name="none">&lt;hiçbiri&gt;</string>
<plurals name="n_keys">
@@ -128,7 +131,6 @@
<!--sentences-->
<string name="no_filemanager_installed">Uyumlu dosya yöneticisi yüklenmedi.</string>
<string name="passphrase_for_symmetric_encryption">Simetrik şifreleme.</string>
- <string name="nfc_text">YubiKey\'inizi cihazınızın arkasında tutun.</string>
<string name="encrypt_sign_successful">Başarıyla imzalandı ve/veya şifrelendi.</string>
<string name="encrypt_sign_clipboard_successful">Kopyalama önbelleğine başarıyla imzalandı ve/veya şifrelendi.</string>
<string name="select_encryption_key">En az bir şifreleme anahtarı seçiniz.</string>
@@ -359,7 +361,7 @@
<string name="create_key_custom">(özel anahtar yapılandırması)</string>
<string name="create_key_edit">Anahtar yapılandırmasını değiştir.</string>
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<string name="nav_keys">Anahtarlar</string>
<string name="nav_apps">Uygulamalar</string>
@@ -415,6 +417,7 @@
<string name="msg_del_error_empty">Silinecek bir şey yok!</string>
<string name="msg_acc_saved">Hesap kaydedildi</string>
<string name="msg_download_success">Başarıyla indirildi!</string>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
@@ -436,7 +439,7 @@
<string name="unknown_algorithm">bilinmeyen</string>
<string name="can_sign_not">imzalanamadı</string>
<string name="error_no_encrypt_subkey">Şifreleme için kullanılabilecek altanahtar mevcut değil!</string>
- <string name="info_no_manual_account_creation">OpenKeychain-hesaplarını kendiniz oluşturmayın.\nDaha fazla bilgi için Yardım bölümüne bakın.</string>
+ <string name="account_no_manual_account_creation">OpenKeychain-hesaplarını kendiniz oluşturmayın.\nDaha fazla bilgi için Yardım bölümüne bakın.</string>
<string name="contact_show_key">Anahtarı göster (%s)</string>
<string name="swipe_to_update">Anahtar sunucudan güncelleme almak için parmağınızı aşağıya doğru kaydırın</string>
<string name="error_no_file_selected">Şifrelemek için en az bir dosya seçin!</string>
diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml
index bcda5026f..40d588bca 100644
--- a/OpenKeychain/src/main/res/values-uk/strings.xml
+++ b/OpenKeychain/src/main/res/values-uk/strings.xml
@@ -66,7 +66,6 @@
<string name="label_use_default_yubikey_pin">Вживати типовий YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Вживати цифрову клавіатуру для YubiKey PIN</string>
<string name="label_label_use_default_yubikey_pin_summary">Вживається типовий PIN (123456) для доступу до YubiKey чреез NFC</string>
- <string name="label_asymmetric_from">Підписано:</string>
<string name="label_to">Зашифрувати до:</string>
<string name="label_delete_after_decryption">Вилучити після розшифрування</string>
<string name="label_encryption_algorithm">Алгоритм шифрування</string>
@@ -85,8 +84,12 @@
<string name="label_send_key">Синхронізувати із хмарою</string>
<string name="label_fingerprint">Відбиток</string>
<string name="expiry_date_dialog_title">Задати термін дії</string>
- <string name="label_first_keyserver_is_used">(Перший наведений сервер ключів є бажаний)</string>
<string name="label_preferred">бажаний</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;без імені&gt;</string>
<string name="none">&lt;жоден&gt;</string>
<plurals name="n_keys">
@@ -305,7 +308,7 @@
<string name="api_settings_start">Запустити програму</string>
<string name="api_settings_delete_account">Видалити профіль</string>
<string name="api_settings_package_name">Назва пакунку</string>
- <string name="api_settings_package_signature">SHA-256 підписку пакунку</string>
+ <string name="api_settings_package_certificate">SHA-256 підписку пакунку</string>
<string name="api_settings_settings">Параметри</string>
<string name="api_settings_accounts_empty">Немає облікового запису приєднаного до цієї програми.</string>
<string name="api_register_allow">Дозволити доступ</string>
@@ -361,7 +364,7 @@
<string name="create_key_empty">Це поле - обов\'язкове</string>
<string name="create_key_final_text">Ви ввели наступну сутність:</string>
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<string name="nav_keys">Ключі</string>
<string name="nav_apps">Програми</string>
@@ -504,6 +507,7 @@
<item quantity="few">частини завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
<item quantity="other">частин завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
</plurals>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-v21/themes.xml b/OpenKeychain/src/main/res/values-v21/themes.xml
index b47026e5b..dab38f97a 100644
--- a/OpenKeychain/src/main/res/values-v21/themes.xml
+++ b/OpenKeychain/src/main/res/values-v21/themes.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="KeychainTheme" parent="KeychainTheme.Base">
+ <style name="LightTheme" parent="LightBaseTheme">
<item name="android:windowTranslucentStatus">true</item>
<!-- enable window content transitions -->
@@ -12,4 +12,17 @@
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>
-</resources> \ No newline at end of file
+
+ <style name="DarkTheme" parent="DarkBaseTheme">
+ <item name="android:windowTranslucentStatus">true</item>
+
+ <!-- enable window content transitions -->
+ <item name="android:windowContentTransitions">true</item>
+ <item name="android:windowAllowEnterTransitionOverlap">true</item>
+ <item name="android:windowAllowReturnTransitionOverlap">true</item>
+ <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
+ <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
+
+ </style>
+
+</resources>
diff --git a/OpenKeychain/src/main/res/values-vi/strings.xml b/OpenKeychain/src/main/res/values-vi/strings.xml
index 8f84af665..0713e39ad 100644
--- a/OpenKeychain/src/main/res/values-vi/strings.xml
+++ b/OpenKeychain/src/main/res/values-vi/strings.xml
@@ -7,6 +7,11 @@
<!--button-->
<!--menu-->
<!--label-->
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<!--choice-->
<!--key flags-->
<!--sentences-->
@@ -42,7 +47,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -61,6 +66,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
index f316ea65d..7005543bc 100644
--- a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
+++ b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
@@ -97,7 +97,6 @@
<string name="label_use_default_yubikey_pin">使用預設的 Yubikey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">輸入 YubiKey PIN 時使用數字鍵盤</string>
<string name="label_label_use_default_yubikey_pin_summary">使用預設的 PIN (123456) 來使用 NFC 存取 Yubikeys</string>
- <string name="label_asymmetric_from">簽名自:</string>
<string name="label_to">加密給:</string>
<string name="label_delete_after_encryption">加密後刪除檔案</string>
<string name="label_delete_after_decryption">解密後刪除檔案</string>
@@ -118,11 +117,15 @@
<string name="label_send_key">與雲端同步</string>
<string name="label_fingerprint">指紋</string>
<string name="expiry_date_dialog_title">設定效期</string>
- <string name="label_first_keyserver_is_used">(先列出的金鑰伺服器爲優先)</string>
<string name="label_preferred">優先</string>
<string name="label_enable_compression">啓用壓縮</string>
<string name="label_encrypt_filenames">加密檔名</string>
<string name="label_hidden_recipients">隱藏收件人</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<string name="user_id_no_name">&lt;無名&gt;</string>
<string name="none">&lt;無&gt;</string>
<plurals name="n_keys">
@@ -172,7 +175,7 @@
<string name="select_encryption_key">選擇至少一把加密金鑰。</string>
<string name="specify_file_to_encrypt_to">請指定欲加密的檔案。\n警告:已經存在的檔案將被覆蓋。</string>
<string name="specify_file_to_decrypt_to">請指定欲解密的檔案。\n警告:已經存在的檔案將被覆蓋。</string>
- <string name="specify_file_to_export_to">請指定欲輸出的檔案。\n警告:已經存在的檔案將被覆蓋。</string>
+ <string name="specify_backup_dest">請指定欲輸出的檔案。\n警告:已經存在的檔案將被覆蓋。</string>
<string name="key_deletion_confirmation_multi">您真的想要刪除所有已選金鑰嗎?</string>
<string name="secret_key_deletion_confirmation">刪除之後您將無法閱讀以這把金鑰加密的訊息,而且所有用這把金鑰做的認證都會失效!</string>
<string name="public_key_deletetion_confirmation">刪除金鑰 \'%s\' ?</string>
@@ -391,7 +394,7 @@
<string name="api_settings_start">開啟應用程式</string>
<string name="api_settings_delete_account">移除帳戶</string>
<string name="api_settings_package_name">打包名稱</string>
- <string name="api_settings_package_signature">SHA-256 所打包的簽章</string>
+ <string name="api_settings_package_certificate">SHA-256 所打包的簽章</string>
<string name="api_settings_accounts">帳戶(舊版API)</string>
<string name="api_settings_advanced">延伸資訊</string>
<string name="api_settings_allowed_keys">允許的金鑰</string>
@@ -499,7 +502,7 @@
<string name="view_key_verified">已確認金鑰</string>
<string name="view_key_unverified">未確認:掃描QR條碼來確認該金鑰!</string>
<string name="view_key_fragment_no_system_contact">&lt;無&gt;</string>
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<string name="add_keyserver_invalid_url">URL無效!</string>
<!--Navigation Drawer-->
<string name="nav_keys">金鑰</string>
@@ -609,6 +612,7 @@
<string name="msg_download_success">下載成功!</string>
<string name="msg_download_no_valid_keys">在檔案/剪貼簿中找不到有效的金鑰!</string>
<string name="msg_download_query_failed">查詢金鑰的時候發生錯誤。</string>
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
@@ -626,7 +630,7 @@
<string name="title_view_cert">查看認證內容</string>
<string name="unknown_algorithm">未知</string>
<string name="error_no_encrypt_subkey">沒有可供加密的子金鑰!</string>
- <string name="info_no_manual_account_creation">請不要自行建立OpenKeychain帳戶。\n更多資訊請參考說明。</string>
+ <string name="account_no_manual_account_creation">請不要自行建立OpenKeychain帳戶。\n更多資訊請參考說明。</string>
<string name="exchange_description">要發起金鑰交換,先在右邊選擇與會人數,然後點選〝開始交換〞。\n\n接下來會詢問你兩個問題,以確保會議成員與交換的指紋是正確的。</string>
<string name="btn_start_exchange">開始交換</string>
<!--Passphrase wizard-->
diff --git a/OpenKeychain/src/main/res/values-zh/strings.xml b/OpenKeychain/src/main/res/values-zh/strings.xml
index 069e3f0bd..180167e3e 100644
--- a/OpenKeychain/src/main/res/values-zh/strings.xml
+++ b/OpenKeychain/src/main/res/values-zh/strings.xml
@@ -106,9 +106,13 @@
<string name="label_email">电子邮件</string>
<string name="label_fingerprint">指纹</string>
<string name="expiry_date_dialog_title">有效期</string>
- <string name="label_first_keyserver_is_used">首选服务器</string>
<string name="label_encrypt_filenames">加密文件名</string>
<string name="pref_keyserver">OpenPGP 密钥服务器</string>
+ <!--Proxy Preferences-->
+ <!--proxy type choices and values-->
+ <!--OrbotHelper strings-->
+ <!--InstallDialogFragment strings-->
+ <!--StartOrbotDialogFragment strings-->
<plurals name="n_keys">
<item quantity="other">其他</item>
</plurals>
@@ -234,7 +238,7 @@
<!--Edit key-->
<!--Create key-->
<!--View key-->
- <!--Add keyserver-->
+ <!--Add/Edit keyserver-->
<!--Navigation Drawer-->
<!--hints-->
<!--certs-->
@@ -253,6 +257,7 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Messages for Keybase Verification operation-->
<!--Messages for Export Log operation-->
<!--PassphraseCache-->
<!--First Time-->
diff --git a/OpenKeychain/src/main/res/values/arrays.xml b/OpenKeychain/src/main/res/values/arrays.xml
index 44bbe00cc..ef3970672 100644
--- a/OpenKeychain/src/main/res/values/arrays.xml
+++ b/OpenKeychain/src/main/res/values/arrays.xml
@@ -29,6 +29,18 @@
<item>28800</item>
<item>-1</item>
</string-array>
+ <string-array name="pref_proxy_type_entries" translatable="false">
+ <item>@string/pref_proxy_type_choice_http</item>
+ <item>@string/pref_proxy_type_choice_socks</item>
+ </string-array>
+ <string-array name="pref_proxy_type_values" translatable="false">
+ <item>@string/pref_proxy_type_value_http</item>
+ <item>@string/pref_proxy_type_value_socks</item>
+ </string-array>
+ <string-array name="rev_del_dialog_entries" translatable="true">
+ <item>@string/del_rev_dialog_choice_rev_upload</item>
+ <item>@string/del_rev_dialog_choice_delete</item>
+ </string-array>
<string-array name="rsa_key_size_spinner_values" translatable="false">
<item>@string/key_size_2048</item>
<item>@string/key_size_4096</item>
@@ -49,4 +61,12 @@
<item>@string/key_size_custom</item>
</string-array>
+ <string-array name="theme_entries" translatable="false">
+ <item>@string/theme_dark</item>
+ <item>@string/theme_light</item>
+ </string-array>
+ <string-array name="theme_values" translatable="false">
+ <item>"dark"</item>
+ <item>"ligh"</item>
+ </string-array>
</resources>
diff --git a/OpenKeychain/src/main/res/values/attrs.xml b/OpenKeychain/src/main/res/values/attrs.xml
new file mode 100644
index 000000000..5c570e62b
--- /dev/null
+++ b/OpenKeychain/src/main/res/values/attrs.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <declare-styleable name="CustomTheme">
+ <attr name="colorFab" format="color" />
+ <attr name="colorFabPressed" format="color" />
+ <attr name="colorFabBackground" format="color" />
+ <attr name="colorFabText" format="color" />
+ <attr name="colorEmphasis" format="color" />
+ <attr name="colorHeaderText" format="color" />
+ <attr name="colorTertiaryText" format="color" />
+ <attr name="colorButtonRow" format="color" />
+ <attr name="colorLogBackground" format="color" />
+ <attr name="colorCardViewHeaderDivider" format="color" />
+ <attr name="colorText" format="color" />
+ <attr name="colorBrightToolbar" format="color" />
+ <attr name="colorCardViewBackground" format="color" />
+ <attr name="colorTabText" format="color" />
+ <attr name="colorTabTextSelected" format="color" />
+ <attr name="colorTabIndicator" format="color" />
+ </declare-styleable>
+</resources>
diff --git a/OpenKeychain/src/main/res/values/colors.xml b/OpenKeychain/src/main/res/values/colors.xml
index ead006a63..5db66b945 100644
--- a/OpenKeychain/src/main/res/values/colors.xml
+++ b/OpenKeychain/src/main/res/values/colors.xml
@@ -1,54 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <!-- Main theme colors -->
-
- <!-- green colors from OpenKeychain logo bottom right -->
- <!-- your app branding color for the app bar -->
<color name="primary">#7bad45</color>
- <!-- darker variant for the status bar and contextual app bars -->
- <color name="primary_dark">#6c983d</color>
- <!-- theme UI controls like checkboxes and text fields -->
- <color name="accent">#2196F3</color>
-
- <!-- Other colors -->
-
- <color name="black">#000000</color>
-
- <color name="primary_light">#C8E6C9</color>
- <color name="fab">@color/accent</color>
- <color name="fab_pressed">#1976D2</color>
- <color name="primary_text">#212121</color>
- <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 -->
- <color name="emphasis">@color/accent</color>
-
- <color name="bg_gray">#cecbce</color>
- <color name="tertiary_text_light">#808080</color>
- <color name="alert">#ffdd3333</color>
-
- <color name="holo_gray_light">#33999999</color>
- <color name="holo_gray_bright">#33CCCCCC</color>
- <!-- tabs -->
- <color name="tab_text">#70FFFFFF</color>
- <color name="tab_text_selected">#FFFFFF</color>
- <color name="tab_indicator">#FFFFFF</color>
+ <color name="icons">#ffffff</color>
+ <color name="transparent">#00ffffff</color>
+ <color name="key_flag_gray">#808080</color>
+ <color name="key_flag_red">#f44336</color>
+ <color name="key_flag_orange">#ff9800</color>
+ <color name="key_flag_green">#7bad45</color>
- <!-- floating action buttons -->
- <color name="black_semi_transparent">#B2000000</color>
- <color name="background">#e5e5e5</color>
- <color name="half_black">#808080</color>
- <color name="white">#fafafa</color>
- <color name="white_pressed">#f1f1f1</color>
+ <color name="password_strength_low">#f44336</color>
+ <color name="password_strength_medium">#ff9800</color>
+ <color name="password_strength_high">#7bad45</color>
<!--
+ Standard Android colors:
http://www.google.com/design/spec/style/color.html#color-color-palette
light = normal color
dark = 900
@@ -58,10 +26,7 @@
<color name="android_red_light">#f44336</color>
<color name="android_red_dark">#b71c1c</color>
<color name="android_orange_light">#ff9800</color>
- <color name="android_orange_dark">#e65100</color>
- <color name="android_green_light">@color/primary</color>
- <color name="android_green_dark">@color/primary_dark</color>
- <color name="android_purple_light">#673ab7</color>
- <color name="android_purple_dark">#311b92</color>
+ <color name="android_green_light">#7bad45</color>
+ <color name="android_green_dark">#6c983d</color>
</resources>
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index a62df862f..0c394bda7 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -25,8 +25,8 @@
<string name="title_encrypt_to_file">"Encrypt To File"</string>
<string name="title_decrypt_to_file">"Decrypt To File"</string>
<string name="title_import_keys">"Import Keys"</string>
- <string name="title_export_key">"Export Key"</string>
- <string name="title_export_keys">"Export Keys"</string>
+ <string name="title_export_key">"Backup Key"</string>
+ <string name="title_export_keys">"Backup Keys"</string>
<string name="title_key_not_found">"Key Not Found"</string>
<string name="title_send_key">"Upload to Keyserver"</string>
<string name="title_certify_key">"Confirm Key"</string>
@@ -49,6 +49,8 @@
<string name="section_keys">"Subkeys"</string>
<string name="section_cloud_search">"Cloud search"</string>
<string name="section_passphrase_cache">"Password/PIN Handling"</string>
+ <string name="section_proxy_settings">"Proxy Settings"</string>
+ <string name="section_gui">"Interface"</string>
<string name="section_certify">"Confirm"</string>
<string name="section_actions">"Actions"</string>
<string name="section_share_key">"Key"</string>
@@ -95,7 +97,7 @@
<!-- menu -->
<string name="menu_preferences">"Settings"</string>
<string name="menu_help">"Help"</string>
- <string name="menu_export_key">"Export to file"</string>
+ <string name="menu_export_key">"Backup to file"</string>
<string name="menu_delete_key">"Delete key"</string>
<string name="menu_manage_keys">"Manage my keys"</string>
<string name="menu_search">"Search"</string>
@@ -109,6 +111,8 @@
<string name="menu_certify_fingerprint">"Confirm via fingerprint comparison"</string>
<string name="menu_export_log">"Export Log"</string>
+ <string name="menu_keyserver_add">"Add"</string>
+
<!-- label -->
<string name="label_message">"Text"</string>
<string name="label_file">"File"</string>
@@ -127,7 +131,7 @@
<string name="label_use_default_yubikey_pin">"Use default YubiKey PIN"</string>
<string name="label_use_num_keypad_for_yubikey_pin">Use number keypad for YubiKey PIN</string>
<string name="label_label_use_default_yubikey_pin_summary">"Uses default PIN (123456) to access YubiKeys over NFC"</string>
- <string name="label_asymmetric_from">"Signed by:"</string>
+ <string name="label_asymmetric_from">"Sign with:"</string>
<string name="label_to">"Encrypt to:"</string>
<string name="label_delete_after_encryption">"Delete files after encryption"</string>
<string name="label_delete_after_decryption">"Delete after decryption"</string>
@@ -153,19 +157,59 @@
<string name="label_send_key">"Synchronize with the cloud"</string>
<string name="label_fingerprint">"Fingerprint"</string>
<string name="expiry_date_dialog_title">"Set expiry date"</string>
- <string name="label_first_keyserver_is_used">"(First keyserver listed is preferred)"</string>
+ <string name="label_keyservers_title">"Keyservers"</string>
+ <string name="label_keyserver_settings_hint">"Drag to change order, tap to edit/delete"</string>
+ <string name="label_selected_keyserver_title">"Selected keyserver"</string>
<string name="label_preferred">"preferred"</string>
<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="label_keyserver_dialog_delete">"Delete keyserver"</string>
+ <string name="label_theme">"Theme"</string>
<string name="pref_keyserver">"OpenPGP keyservers"</string>
<string name="pref_keyserver_summary">"Search keys on selected OpenPGP keyservers (HKP protocol)"</string>
<string name="pref_keybase">"keybase.io"</string>
<string name="pref_keybase_summary">"Search keys on keybase.io"</string>
+ <!-- Proxy Preferences -->
+ <string name="pref_proxy_tor_title">"Enable Tor"</string>
+ <string name="pref_proxy_tor_summary">"Requires Orbot to be installed"</string>
+ <string name="pref_proxy_normal_title">"Enable other proxy"</string>
+ <string name="pref_proxy_host_title">"Proxy Host"</string>
+ <string name="pref_proxy_host_err_invalid">"Proxy host cannot be empty"</string>
+ <string name="pref_proxy_port_title">"Proxy Port"</string>
+ <string name="pref_proxy_port_err_invalid">"Invalid port number entered"</string>
+ <string name="pref_proxy_type_title">"Proxy Type"</string>
+
+ <!-- proxy type choices and values -->
+ <string name="pref_proxy_type_choice_http">"HTTP"</string>
+ <string name="pref_proxy_type_choice_socks">"SOCKS"</string>
+ <string name="pref_proxy_type_value_http">"proxyHttp"</string>
+ <string name="pref_proxy_type_value_socks">"proxySocks"</string>
+
+ <!-- OrbotHelper strings -->
+ <string name="orbot_ignore_tor">"Don\'t use Tor"</string>
+
+ <!-- InstallDialogFragment strings -->
+ <string name="orbot_install_dialog_title">Install Orbot to use Tor?</string>
+ <string name="orbot_install_dialog_install">"Install"</string>
+ <string name="orbot_install_dialog_content">You must have Orbot installed and activated to proxy traffic through it. Would you like to install it?</string>
+ <string name="orbot_install_dialog_cancel">"Cancel"</string>
+ <string name="orbot_install_dialog_ignore_tor">"Don\'t use Tor"</string>
+
+ <!-- StartOrbotDialogFragment strings -->
+ <string name="orbot_start_dialog_title">Start Orbot?</string>
+ <string name="orbot_start_dialog_content">"Orbot doesn\'t appear to be running. Would you like to start it up and connect to Tor?"</string>
+ <string name="orbot_start_btn">"Start Orbot"</string>
+ <string name="orbot_start_dialog_start">"Start Orbot"</string>
+ <string name="orbot_start_dialog_cancel">"Cancel"</string>
+ <string name="orbot_start_dialog_ignore_tor">"Don\'t use Tor"</string>
+
+
<string name="user_id_no_name">"&lt;no name&gt;"</string>
<string name="none">"&lt;none&gt;"</string>
@@ -203,6 +247,8 @@
<string name="filemanager_title_open">"Open…"</string>
<string name="error">"Error"</string>
<string name="error_message">"Error: %s"</string>
+ <string name="theme_dark">"Dark"</string>
+ <string name="theme_light">"Light"</string>
<!-- key flags -->
<string name="flag_certify">"Certify"</string>
@@ -219,7 +265,10 @@
<string name="passphrase_for">"Enter password for '%s'"</string>
<string name="pin_for">"Enter PIN for '%s'"</string>
<string name="yubikey_pin_for">"Enter PIN to access YubiKey for '%s'"</string>
- <string name="nfc_text">"Hold YubiKey against the back of your device."</string>
+ <string name="nfc_text">"Hold YubiKey against the NFC marker at the back of your device."</string>
+ <string name="nfc_wait">"Keep the YubiKey at the back!"</string>
+ <string name="nfc_finished">"Take away the YubiKey now."</string>
+ <string name="nfc_try_again_text">"Take away the YubiKey now and press TRY AGAIN."</string>
<string name="file_delete_confirmation_title">"Delete original files?"</string>
<string name="file_delete_confirmation">"The following files will be deleted:%s"</string>
<string name="file_delete_successful">"%1$d out of %2$d files have been deleted.%3$s"</string>
@@ -230,7 +279,10 @@
<string name="error_no_encryption_or_signature_key">"Select at least one encryption key or a signature key."</string>
<string name="specify_file_to_encrypt_to">"Please specify which file to encrypt to.\nWARNING: File will be overwritten if it exists!"</string>
<string name="specify_file_to_decrypt_to">"Please specify which file to decrypt to.\nWARNING: File will be overwritten if it exists!"</string>
- <string name="specify_file_to_export_to">"Please specify which file to export to.\nWARNING: File will be overwritten if it exists!"</string>
+ <string name="specify_backup_dest">"A backup excluding your keys will be made, please specify a destination file.\nWARNING: File will be overwritten if it exists!"</string>
+ <string name="specify_backup_dest_single">"This key will be shared, please specify a destination file.\nWARNING: File will be overwritten if it exists!"</string>
+ <string name="specify_backup_dest_secret_single">"A full backup of your key will be made, please specify a destination file.\nWARNING: File will be overwritten if it exists!"</string>
+ <string name="specify_backup_dest_secret">"A full backup of all keys including yours will be made, please specify a destination file.\nWARNING: File will be overwritten if it exists!"</string>
<string name="key_deletion_confirmation_multi">"Do you really want to delete all selected keys?"</string>
<string name="secret_key_deletion_confirmation">"After deletion you will not be able to read messages encrypted with this key and lose all key confirmations done with it!"</string>
<string name="public_key_deletetion_confirmation">"Delete key '%s'?"</string>
@@ -313,6 +365,7 @@
<string name="progress_cancelling">"cancelling…"</string>
<string name="progress_saving">"saving…"</string>
<string name="progress_importing">"importing…"</string>
+ <string name="progress_revoking_uploading">"Revoking and uploading key…"</string>
<string name="progress_updating">"Updating keys…"</string>
<string name="progress_exporting">"exporting…"</string>
<string name="progress_uploading">"uploading…"</string>
@@ -336,6 +389,8 @@
<string name="progress_modify_subkeystrip">"stripping subkeys…"</string>
<string name="progress_modify_subkeyadd">"adding subkeys…"</string>
<string name="progress_modify_passphrase">"changing password…"</string>
+ <string name="progress_modify_pin">"changing PIN…"</string>
+ <string name="progress_modify_admin_pin">"changing Admin PIN…"</string>
<plurals name="progress_exporting_key">
<item quantity="one">"exporting key…"</item>
@@ -474,6 +529,12 @@
<string name="delete_nothing">"Nothing to delete."</string>
<string name="delete_cancelled">"Delete operation cancelled."</string>
+ <!-- Revoke result toast (snackbar) -->
+ <string name="revoke_ok">"Successfully revoked key."</string>
+ <string name="revoke_fail">"Error revoking key!"</string>
+ <string name="revoke_nothing">"Nothing to revoke."</string>
+ <string name="revoke_cancelled">"Revoke operation cancelled."</string>
+
<!-- Certify result toast -->
<plurals name="certify_keys_ok">
<item quantity="one">"Successfully certified key%2$s."</item>
@@ -509,7 +570,7 @@
<string name="api_settings_start">"Start application"</string>
<string name="api_settings_delete_account">"Delete account"</string>
<string name="api_settings_package_name">"Package Name"</string>
- <string name="api_settings_package_signature">"SHA-256 of Package Signature"</string>
+ <string name="api_settings_package_certificate">"SHA-256 of Package Certificate"</string>
<string name="api_settings_accounts">"Accounts (old API)"</string>
<string name="api_settings_advanced">"Extended Information"</string>
<string name="api_settings_allowed_keys">"Allowed Keys"</string>
@@ -522,8 +583,8 @@
<string name="api_register_allow">"Allow access"</string>
<string name="api_register_disallow">"Disallow access"</string>
<string name="api_register_error_select_key">"Please select a key!"</string>
- <string name="api_select_pub_keys_missing_text">"No keys were found for these identities:"</string>
- <string name="api_select_pub_keys_dublicates_text">"More than one key exist for these identities:"</string>
+ <string name="api_select_pub_keys_missing_text">"No keys were found for these email addresses:"</string>
+ <string name="api_select_pub_keys_dublicates_text">"More than one key exist for these email addresses:"</string>
<string name="api_select_pub_keys_text">"Please review the list of recipients!"</string>
<string name="api_select_pub_keys_text_no_user_ids">"Please select the recipients!"</string>
<string name="api_error_wrong_signature">"Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app's registration in OpenKeychain and then register the app again."</string>
@@ -534,6 +595,23 @@
<string name="share_qr_code_dialog_title">"Share with QR Code"</string>
<string name="share_nfc_dialog">"Share with NFC"</string>
+ <!-- retry upload dialog -->
+ <string name="retry_up_dialog_title">"Upload failed"</string>
+ <string name="retry_up_dialog_message">"Upload failed. Would you like to retry the operation?"</string>
+ <string name="retry_up_dialog_btn_reupload">"Retry Operation"</string>
+ <string name="retry_up_dialog_btn_cancel">"Cancel Operation"</string>
+
+ <!-- Delete or revoke private key dialog -->
+ <string name="del_rev_dialog_message">"If you would no longer like to use this key, it should be revoked and uploaded. Select delete only if you wish to remove the key from OpenKeychain but continue to use it from somewhere else."</string>
+ <string name="del_rev_dialog_title">"Revoke/Delete key \"%s\""</string>
+ <string name="del_rev_dialog_btn_revoke">"Revoke and upload"</string>
+ <string name="del_rev_dialog_btn_delete">"Delete only"</string>
+
+ <!-- Delete Or Revoke Dialog spinner -->
+ <string name="del_rev_dialog_choice_delete">"Delete only"</string>
+ <string name="del_rev_dialog_choice_rev_upload">"Revoke and Upload"</string>
+
+
<!-- Key list -->
<plurals name="key_list_selected_keys">
<item quantity="one">"1 key selected."</item>
@@ -654,6 +732,13 @@
<string name="create_key_add_email_text">"Additional email addresses are also associated to this key and can be used for secure communication."</string>
<string name="create_key_email_already_exists_text">"Email address has already been added"</string>
<string name="create_key_email_invalid_email">"Email address format is invalid"</string>
+ <string name="create_key_yubi_key_pin_text">"Please remember the PIN, it is required to use your YubiKey later. Please write down the Admin PIN and store it in a safe place."</string>
+ <string name="create_key_yubi_key_pin">"PIN"</string>
+ <string name="create_key_yubi_key_admin_pin">"Admin PIN"</string>
+ <string name="create_key_yubi_key_pin_repeat_text">"Please enter the PIN and Admin PIN to proceed."</string>
+ <string name="create_key_yubi_key_pin_repeat">"Repeat PIN"</string>
+ <string name="create_key_yubi_key_admin_pin_repeat">"Repeat Admin PIN"</string>
+ <string name="create_key_yubi_key_pin_not_correct">"PIN is not correct!"</string>
<!-- View key -->
<string name="view_key_revoked">"Revoked: Key must not be used anymore!"</string>
@@ -665,12 +750,15 @@
<string name="view_key_fragment_no_system_contact">"&lt;none&gt;"</string>
- <!-- Add keyserver -->
+ <!-- Add/Edit keyserver -->
<string name="add_keyserver_dialog_title">"Add keyserver"</string>
+ <string name="edit_keyserver_dialog_title">"Edit 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>
+ <string name="keyserver_preference_deleted">"%s deleted"</string>
+ <string name="keyserver_preference_cannot_delete_last">"Cannot delete last keyserver. At least one is required!"</string>
<!-- Navigation Drawer -->
<string name="nav_keys">"Keys"</string>
@@ -679,6 +767,7 @@
<string name="drawer_open">"Open navigation drawer"</string>
<string name="drawer_close">"Close navigation drawer"</string>
<string name="my_keys">"My Keys"</string>
+ <string name="nav_backup">"Backup"</string>
<!-- hints -->
<string name="encrypt_content_edit_text_hint">"Type text"</string>
@@ -919,6 +1008,7 @@
<!-- modifySecretKeyRing -->
<string name="msg_mr">"Modifying keyring %s"</string>
<string name="msg_mf_divert">"Will divert to smart card for crypto operations"</string>
+ <string name="msg_mf_error_divert_newsub">"Creation of new subkeys is not supported for 'divert-to-card' primary keys!"</string>
<string name="msg_mf_error_divert_serial">"The serial number of a 'divert-to-card' key must be 16 bytes! This is a programming error, please file a bug report!"</string>
<string name="msg_mf_error_encode">"Encoding exception!"</string>
<string name="msg_mf_error_fingerprint">"Actual key fingerprint does not match the expected one!"</string>
@@ -934,6 +1024,7 @@
<string name="msg_mf_error_passphrase_master">"Fatal error decrypting master key! This is likely a programming error, please file a bug report!"</string>
<string name="msg_mf_error_pgp">"Internal OpenPGP error!"</string>
<string name="msg_mf_error_sig">"Signature exception!"</string>
+ <string name="msg_mf_error_sub_stripped">"Cannot modify stripped subkey %s!"</string>
<string name="msg_mf_error_subkey_missing">"Tried to operate on missing subkey %s!"</string>
<string name="msg_mf_error_conflicting_nfc_commands">"Cannot move key to smart card in same operation that creates an on-card signature."</string>
<string name="msg_mf_error_duplicate_keytocard_for_slot">"Smart card supports only one slot per key type."</string>
@@ -942,6 +1033,8 @@
<string name="msg_mf_notation_empty">"Adding empty notation packet"</string>
<string name="msg_mf_notation_pin">"Adding PIN notation packet"</string>
<string name="msg_mf_passphrase">"Changing password for keyring"</string>
+ <string name="msg_mf_pin">"Changing PIN on card"</string>
+ <string name="msg_mf_admin_pin">"Changing Admin PIN on card"</string>
<string name="msg_mf_passphrase_key">"Re-encrypting subkey %s with new password"</string>
<string name="msg_mf_passphrase_empty_retry">"Setting new password failed, trying again with empty old password"</string>
<string name="msg_mf_passphrase_fail">"Password for subkey could not be changed! (Does it have a different one from the other keys?)"</string>
@@ -1007,6 +1100,7 @@
<string name="msg_ed_caching_new">"Caching new password"</string>
<string name="msg_ed_error_no_parcel">"Missing SaveKeyringParcel! (this is a bug, please report)"</string>
<string name="msg_ed_error_key_not_found">"Key not found!"</string>
+ <string name="msg_ed_error_extract_public_upload">"Error extracting public key for upload!"</string>
<string name="msg_ed_fetching">"Fetching key to modify (%s)"</string>
<string name="msg_ed_success">"Key operation successful"</string>
@@ -1042,12 +1136,14 @@
<string name="msg_dc_clear_signature">"Saving signature data for later"</string>
<string name="msg_dc_clear">"Processing cleartext data"</string>
<string name="msg_dc_error_bad_passphrase">"Error unlocking key, bad password!"</string>
+ <string name="msg_dc_error_sym_passphrase">"Error decrypting data! (Bad passphrase?)"</string>
<string name="msg_dc_error_corrupt_data">"Data is corrupt!"</string>
<string name="msg_dc_error_extract_key">"Unknown error unlocking key!"</string>
<string name="msg_dc_error_integrity_check">"Integrity check error!"</string>
<string name="msg_dc_error_integrity_missing">"Missing integrity check! This can happen because the encrypting application is out of date, or from a downgrade attack."</string>
<string name="msg_dc_error_invalid_data">"No valid OpenPGP encrypted or signed data found!"</string>
- <string name="msg_dc_error_io">"Encountered IO Exception during operation!"</string>
+ <string name="msg_dc_error_io">"Encountered an error reading input data!"</string>
+ <string name="msg_dc_error_input">"Error opening input data stream!"</string>
<string name="msg_dc_error_no_data">"No encrypted data found in stream!"</string>
<string name="msg_dc_error_no_key">"No encrypted data with known secret key found in stream!"</string>
<string name="msg_dc_error_pgp_exception">"Encountered OpenPGP Exception during operation!"</string>
@@ -1141,6 +1237,7 @@
<string name="msg_crt_warn_not_found">"Key not found!"</string>
<string name="msg_crt_warn_cert_failed">"Certificate generation failed!"</string>
<string name="msg_crt_warn_save_failed">"Save operation failed!"</string>
+ <string name="msg_crt_warn_upload_failed">"Upload operation failed!"</string>
<string name="msg_crt_upload_success">"Successfully uploaded key to server"</string>
@@ -1170,6 +1267,7 @@
</plurals>
<string name="msg_export_all">"Exporting all keys"</string>
<string name="msg_export_public">"Exporting public key %s"</string>
+ <string name="msg_export_upload_public">"Uploading public key %s"</string>
<string name="msg_export_secret">"Exporting secret key %s"</string>
<string name="msg_export_error_no_file">"No filename specified!"</string>
<string name="msg_export_error_fopen">"Error opening file!"</string>
@@ -1179,7 +1277,9 @@
<string name="msg_export_error_db">"Database error!"</string>
<string name="msg_export_error_io">"Input/output error!"</string>
<string name="msg_export_error_key">"Error preprocessing key data!"</string>
+ <string name="msg_export_error_upload">"Error uploading key to server! Please check your internet connection"</string>
<string name="msg_export_success">"Export operation successful"</string>
+ <string name="msg_export_upload_success">"Upload to keyserver successful"</string>
<string name="msg_del_error_empty">"Nothing to delete!"</string>
<string name="msg_del_error_multi_secret">"Secret keys can only be deleted individually!"</string>
@@ -1199,6 +1299,13 @@
<item quantity="other">"Failed to delete %d keys"</item>
</plurals>
+ <string name="msg_revoke_error_empty">"Nothing to revoke!"</string>
+ <string name="msg_revoke_error_multi_secret">"Secret keys can only be revoked individually!"</string>
+ <string name="msg_revoke_error_not_found">"Cannot find key to revoke!"</string>
+ <string name="msg_revoke_key">"Revoking key %s"</string>
+ <string name="msg_revoke_key_fail">"Failed revoking key"</string>
+ <string name="msg_revoke_ok">"Successfully revoked key"</string>
+
<string name="msg_acc_saved">"Account saved"</string>
<string name="msg_download_success">"Downloaded successfully!"</string>
@@ -1249,6 +1356,11 @@
<string name="first_time_blank_yubikey">"Would you like to use this blank YubiKey NEO with OpenKeychain?\n\nPlease take away the YubiKey now, you will be prompted when it is needed again!"</string>
<string name="first_time_blank_yubikey_yes">"Use this YubiKey"</string>
+ <string name="backup_text">"Backups that include your own keys must never be shared with other people!"</string>
+ <string name="backup_all">"All keys + your own keys"</string>
+ <string name="backup_public_keys">"All keys"</string>
+ <string name="backup_section">"Backup"</string>
+
<!-- unsorted -->
<string name="section_certifier_id">"Certifier"</string>
<string name="section_cert">"Certificate Details"</string>
@@ -1273,7 +1385,6 @@
<string name="unknown_algorithm">"unknown"</string>
<string name="can_sign_not">"cannot sign"</string>
<string name="error_no_encrypt_subkey">"No encryption subkey available!"</string>
- <string name="info_no_manual_account_creation">"Do not create OpenKeychain-Accounts manually.\nFor more information, see Help."</string>
<string name="contact_show_key">"Show key (%s)"</string>
<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>
@@ -1286,6 +1397,11 @@
<string name="btn_start_exchange">"Start exchange"</string>
<string name="user_id_none"><![CDATA[<none>]]></string>
+ <!-- Android Account -->
+ <string name="account_no_manual_account_creation">"You can not create OpenKeychain accounts manually."</string>
+ <string name="account_privacy_title">"Privacy"</string>
+ <string name="account_privacy_text">"OpenKeychain does not synchronize your contacts with the Internet. It only links contacts to keys based on names and email addresses. It does this offline on your device."</string>
+
<!-- Passphrase wizard -->
<!-- TODO: rename all the things! -->
<string name="title_unlock_method">Choose an unlock method</string>
@@ -1325,17 +1441,22 @@
<string name="btn_import">"Import"</string>
<string name="snack_yubi_other">Different key stored on YubiKey!</string>
<string name="error_nfc">"NFC Error: %s"</string>
- <string name="error_pin">"NFC: Incorrect PIN; %d tries remaining."</string>
- <string name="error_nfc_terminated">"NFC: Smart card in termination state"</string>
- <string name="error_nfc_wrong_length">"NFC: Wrong length for sent / received data"</string>
- <string name="error_nfc_conditions_not_satisfied">"NFC: Conditions of use not satisfied"</string>
- <string name="error_nfc_security_not_satisfied">"NFC: Security status not satisfied"</string>
- <string name="error_nfc_authentication_blocked">"NFC: PIN blocked after too many attempts"</string>
- <string name="error_nfc_data_not_found">"NFC: Key or object not found"</string>
- <string name="error_nfc_unknown">"NFC: Unknown Error"</string>
- <string name="error_nfc_bad_data">"NFC: Card reported invalid data"</string>
- <string name="error_nfc_chaining_error">"NFC: Card expected last command in a chain"</string>
- <string name="error_nfc_header">"NFC: Card reported invalid %s byte"</string>
+ <plurals name="error_pin">
+ <item quantity="one">"Incorrect PIN!\n%d try remaining."</item>
+ <item quantity="other">"Incorrect PIN!\n%d tries remaining."</item>
+ </plurals>
+ <string name="error_nfc_terminated">"YubiKey in termination state."</string>
+ <string name="error_nfc_wrong_length">"Entered PIN is too short. PINs are at least 6 digits long."</string>
+ <string name="error_nfc_conditions_not_satisfied">"Conditions of use not satisfied."</string>
+ <string name="error_nfc_security_not_satisfied">"Security status not satisfied."</string>
+ <string name="error_nfc_authentication_blocked">"PIN blocked after too many attempts."</string>
+ <string name="error_nfc_data_not_found">"Key or object not found."</string>
+ <string name="error_nfc_unknown">"Unknown Error"</string>
+ <string name="error_nfc_bad_data">"YubiKey reported invalid data."</string>
+ <string name="error_nfc_chaining_error">"YubiKey expected last command in a chain."</string>
+ <string name="error_nfc_header">"YubiKey reported invalid %s byte."</string>
+ <string name="error_nfc_tag_lost">"YubiKey has been taken off too early. Keep the YubiKey at the back until the operation finishes."</string>
+ <string name="error_nfc_try_again">"Try again"</string>
<string name="error_pin_nodefault">Default PIN was rejected!</string>
<string name="error_temp_file">Error creating temporary file.</string>
<string name="btn_delete_original">Delete original file</string>
@@ -1362,5 +1483,9 @@
<string name="file_delete_none">"No file deleted! (Already deleted?)"</string>
<string name="file_delete_exception">"Original file could not be deleted!"</string>
<string name="error_clipboard_empty">"Clipboard is empty!"</string>
+ <string name="error_clipboard_copy">"Error copying data to clipboard!"</string>
+ <string name="error_scan_fp">"Error scanning fingerprint!"</string>
+ <string name="error_scan_match">"Fingerprints did not match!"</string>
+ <string name="error_expiry_past">"Expiry date is in the past!"</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values/styles.xml b/OpenKeychain/src/main/res/values/styles.xml
index 9ac60c397..73a594ac4 100644
--- a/OpenKeychain/src/main/res/values/styles.xml
+++ b/OpenKeychain/src/main/res/values/styles.xml
@@ -7,7 +7,7 @@
<item name="android:layout_marginTop">16dp</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:textStyle">normal</item>
- <item name="android:textColor">@color/header_text</item>
+ <item name="android:textColor">?attr/colorHeaderText</item>
<item name="android:textSize">17sp</item>
</style>
@@ -17,13 +17,21 @@
<item name="android:layout_marginTop">8dp</item>
<item name="android:paddingLeft">8dp</item>
<item name="android:textStyle">bold</item>
- <item name="android:textColor">@color/header_text</item>
+ <item name="android:textColor">?attr/colorHeaderText</item>
<item name="android:textSize">14sp</item>
</style>
<style name="FabMenuStyle">
<item name="android:background">@drawable/fab_label_background</item>
- <item name="android:textColor">@color/white</item>
+ <item name="android:textColor">?attr/colorFabText</item>
</style>
-</resources> \ No newline at end of file
+ <!-- This style is for use with our drag and drop RecyclerView since ItemDecoration did not
+ move with the drag -->
+ <style name="Divider">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">2dp</item>
+ <item name="android:background">?android:attr/listDivider</item>
+ </style>
+
+</resources>
diff --git a/OpenKeychain/src/main/res/values/themes.xml b/OpenKeychain/src/main/res/values/themes.xml
index 6ac09c5d7..3bdbf811d 100644
--- a/OpenKeychain/src/main/res/values/themes.xml
+++ b/OpenKeychain/src/main/res/values/themes.xml
@@ -1,12 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="KeychainTheme" parent="KeychainTheme.Base" />
+ <style name="LightBaseTheme" parent="Theme.AppCompat.Light">
+ <item name="colorPrimary">#7bad45</item>
+ <item name="colorPrimaryDark">#6c983d</item>
+ <item name="colorAccent">#2196f3</item>
+ <item name="colorBrightToolbar">#dddddd</item>
- <style name="KeychainTheme.Base" parent="Theme.AppCompat.Light">
- <item name="colorPrimary">@color/primary</item>
- <item name="colorPrimaryDark">@color/primary_dark</item>
- <item name="colorAccent">@color/accent</item>
+ <item name="colorFab">#2196f3</item>
+ <item name="colorFabPressed">#1976d2</item>
+ <item name="colorFabBackground">#b2000000</item>
+ <item name="colorFabText">#fafafa</item>
+
+ <item name="colorTabText">#70ffffff</item>
+ <item name="colorTabTextSelected">#ffffff</item>
+ <item name="colorTabIndicator">#ffffff</item>
+
+ <item name="colorEmphasis">#2196f3</item>
+ <item name="colorButtonRow">#33cccccc</item>
+ <item name="colorLogBackground">#cecbce</item>
+ <item name="colorCardViewHeaderDivider">#808080</item>
+ <item name="colorCardViewBackground">#ffffff</item>
+
+ <item name="colorText">#000000</item>
+ <item name="colorHeaderText">#212121</item>
+ <item name="colorTertiaryText">#808080</item>
<!-- remove actionbar and title, we use toolbar! -->
<item name="windowNoTitle">true</item>
@@ -16,6 +34,47 @@
<item name="searchViewStyle">@style/MySearchViewStyle</item>
</style>
+ <style name="DarkBaseTheme" parent="MaterialDrawerTheme.ActionBar">
+ <item name="colorPrimary">#268bd2</item>
+ <item name="colorPrimaryDark">#166bb2</item>
+ <item name="colorAccent">#2196f3</item>
+ <item name="colorBrightToolbar">#808080</item>
+
+ <item name="colorFab">#2196f3</item>
+ <item name="colorFabPressed">#1976d2</item>
+ <item name="colorFabBackground">#b2000000</item>
+ <item name="colorFabText">#fafafa</item>
+
+ <item name="colorTabText">#70ffffff</item>
+ <item name="colorTabTextSelected">#ffffff</item>
+ <item name="colorTabIndicator">#ffffff</item>
+
+ <item name="colorEmphasis">#2196f3</item>
+ <item name="colorButtonRow">#33cccccc</item>
+ <item name="colorLogBackground">#303030</item>
+ <item name="colorCardViewHeaderDivider">#808080</item>
+ <item name="colorCardViewBackground">#505050</item>
+
+ <item name="colorText">#ffffff</item>
+ <item name="colorHeaderText">#d0d0d0</item>
+ <item name="colorTertiaryText">#808080</item>
+
+ <item name="material_drawer_selected_text">#268bd2</item>
+
+ <!-- remove actionbar and title, we use toolbar! -->
+ <item name="windowNoTitle">true</item>
+ <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>
+ </style>
+
+ <style name="LightTheme" parent="LightBaseTheme">
+ </style>
+
+ <style name="DarkTheme" parent="DarkBaseTheme">
+ </style>
+
<!-- http://android-developers.blogspot.de/2014/10/appcompat-v21-material-design-for-pre.html -->
<style name="MySearchViewStyle" parent="Widget.AppCompat.SearchView">
<!-- Background for the search query section (e.g. EditText) -->
@@ -35,4 +94,9 @@
<!-- Layout for query suggestion rows -->
<!--<item name="suggestionRowLayout">...</item>-->
</style>
-</resources> \ No newline at end of file
+
+ <style name="KeychainTheme.YubiKeyDialog" parent="@style/Theme.AppCompat.Light.Dialog.MinWidth">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+</resources>
diff --git a/OpenKeychain/src/main/res/xml/account_desc.xml b/OpenKeychain/src/main/res/xml/account_desc.xml
index 6d8d76b02..e04160c5c 100644
--- a/OpenKeychain/src/main/res/xml/account_desc.xml
+++ b/OpenKeychain/src/main/res/xml/account_desc.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountPreferences="@xml/account_preferences"
android:accountType="@string/account_type"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" />
diff --git a/OpenKeychain/src/main/res/xml/account_preferences.xml b/OpenKeychain/src/main/res/xml/account_preferences.xml
new file mode 100644
index 000000000..3fdb54f1e
--- /dev/null
+++ b/OpenKeychain/src/main/res/xml/account_preferences.xml
@@ -0,0 +1,10 @@
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <PreferenceCategory android:title="@string/account_privacy_title" />
+
+ <Preference
+ android:persistent="false"
+ android:selectable="false"
+ android:summary="@string/account_privacy_text" />
+
+</PreferenceScreen> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/xml/gui_preferences.xml b/OpenKeychain/src/main/res/xml/gui_preferences.xml
new file mode 100644
index 000000000..cda7beeef
--- /dev/null
+++ b/OpenKeychain/src/main/res/xml/gui_preferences.xml
@@ -0,0 +1,10 @@
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <ListPreference
+ android:persistent="false"
+ android:key="theme"
+ android:title="@string/label_theme"
+ android:entries="@array/theme_entries"
+ android:entryValues="@array/theme_values"
+ android:dialogTitle="@string/label_theme" />
+
+</PreferenceScreen>
diff --git a/OpenKeychain/src/main/res/xml/preference_headers.xml b/OpenKeychain/src/main/res/xml/preference_headers.xml
index e3447ff48..b7512b062 100644
--- a/OpenKeychain/src/main/res/xml/preference_headers.xml
+++ b/OpenKeychain/src/main/res/xml/preference_headers.xml
@@ -1,8 +1,14 @@
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+ <!--<header-->
+ <!--android:fragment="org.sufficientlysecure.keychain.ui.SettingsActivity$GuiPrefsFragment"-->
+ <!--android:title="@string/section_gui" />-->
<header
android:fragment="org.sufficientlysecure.keychain.ui.SettingsActivity$CloudSearchPrefsFragment"
android:title="@string/section_cloud_search" />
<header
android:fragment="org.sufficientlysecure.keychain.ui.SettingsActivity$AdvancedPrefsFragment"
android:title="@string/section_passphrase_cache" />
+ <header
+ android:fragment="org.sufficientlysecure.keychain.ui.SettingsActivity$ProxyPrefsFragment"
+ android:title="@string/section_proxy_settings" />
</preference-headers>
diff --git a/OpenKeychain/src/main/res/xml/proxy_prefs.xml b/OpenKeychain/src/main/res/xml/proxy_prefs.xml
new file mode 100644
index 000000000..94e101cb6
--- /dev/null
+++ b/OpenKeychain/src/main/res/xml/proxy_prefs.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <CheckBoxPreference
+ android:key="useTorProxy"
+ android:persistent="true"
+ android:title="@string/pref_proxy_tor_title"
+ android:summary="@string/pref_proxy_tor_summary" />
+ <CheckBoxPreference
+ android:key="useNormalProxy"
+ android:persistent="true"
+ android:title="@string/pref_proxy_normal_title" />
+ <EditTextPreference
+ android:key="proxyHost"
+ android:persistent="true"
+ android:defaultValue="127.0.0.1"
+ android:title="@string/pref_proxy_host_title"
+ android:cursorVisible="true"
+ android:textCursorDrawable="@null"
+ android:inputType="textEmailAddress"/>
+ <EditTextPreference
+ android:key="proxyPort"
+ android:defaultValue="8118"
+ android:persistent="true"
+ android:title="@string/pref_proxy_port_title"
+ android:textCursorDrawable="@null"
+ android:inputType="number" />
+ <ListPreference
+ android:entries="@array/pref_proxy_type_entries"
+ android:entryValues="@array/pref_proxy_type_values"
+ android:defaultValue="@string/pref_proxy_type_value_http"
+ android:key="proxyType"
+ android:persistent="true"
+ android:title="@string/pref_proxy_type_title" />
+</PreferenceScreen>
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
index 6984f126e..472e4507a 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
@@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.util.TestingUtils;
import java.io.PrintStream;
import java.security.Security;
import java.util.ArrayList;
+import java.util.Date;
import java.util.Random;
@RunWith(RobolectricGradleTestRunner.class)
@@ -158,7 +159,7 @@ public class CertifyOperationTest {
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds()));
- CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
+ CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), mKeyPhrase1));
Assert.assertTrue("certification must succeed", result.success());
@@ -186,7 +187,7 @@ public class CertifyOperationTest {
CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId());
actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), null,
mStaticRing2.getPublicKey().getUnorderedUserAttributes()));
- CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
+ CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), mKeyPhrase1));
Assert.assertTrue("certification must succeed", result.success());
@@ -209,7 +210,7 @@ public class CertifyOperationTest {
actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds()));
- CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
+ CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), mKeyPhrase1));
Assert.assertFalse("certification with itself must fail!", result.success());
Assert.assertTrue("error msg must be about self certification",
@@ -228,7 +229,8 @@ public class CertifyOperationTest {
uids.add("nonexistent");
actions.add(new CertifyAction(1234L, uids));
- CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
+ CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(),
+ mKeyPhrase1));
Assert.assertFalse("certification of nonexistent key must fail", result.success());
Assert.assertTrue("must contain error msg about not found",
@@ -240,7 +242,8 @@ public class CertifyOperationTest {
actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(),
mStaticRing2.getPublicKey().getUnorderedUserIds()));
- CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1));
+ CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(),
+ mKeyPhrase1));
Assert.assertFalse("certification of nonexistent key must fail", result.success());
Assert.assertTrue("must contain error msg about not found",
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java
index 4eaee4c48..a4854d7b9 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java
@@ -17,21 +17,23 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.io.PrintStream;
+import java.security.Security;
+import java.util.Iterator;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner;
-import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.util.encoders.Hex;
-import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
@@ -43,6 +45,7 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
@@ -51,10 +54,6 @@ import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
import org.sufficientlysecure.keychain.util.TestingUtils;
-import java.io.PrintStream;
-import java.security.Security;
-import java.util.Iterator;
-
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = WorkaroundBuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml")
public class PromoteKeyOperationTest {
@@ -110,7 +109,7 @@ public class PromoteKeyOperationTest {
PromoteKeyOperation op = new PromoteKeyOperation(RuntimeEnvironment.application,
new ProviderHelper(RuntimeEnvironment.application), null, null);
- PromoteKeyResult result = op.execute(mStaticRing.getMasterKeyId(), null, null);
+ PromoteKeyResult result = op.execute(new PromoteKeyringParcel(mStaticRing.getMasterKeyId(), null, null), null);
Assert.assertTrue("promotion must succeed", result.success());
@@ -136,7 +135,7 @@ public class PromoteKeyOperationTest {
byte[] aid = Hex.decode("D2760001240102000000012345670000");
- PromoteKeyResult result = op.execute(mStaticRing.getMasterKeyId(), aid, null);
+ PromoteKeyResult result = op.execute(new PromoteKeyringParcel(mStaticRing.getMasterKeyId(), aid, null), null);
Assert.assertTrue("promotion must succeed", result.success());
@@ -164,9 +163,9 @@ public class PromoteKeyOperationTest {
// only promote the first, rest stays dummy
long keyId = KeyringTestingHelper.getSubkeyId(mStaticRing, 1);
- PromoteKeyResult result = op.execute(mStaticRing.getMasterKeyId(), aid, new long[] {
+ PromoteKeyResult result = op.execute(new PromoteKeyringParcel(mStaticRing.getMasterKeyId(), aid, new long[] {
keyId
- });
+ }), null);
Assert.assertTrue("promotion must succeed", result.success());
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java
index 9c3636d07..edd7880fc 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java
@@ -17,6 +17,16 @@
package org.sufficientlysecure.keychain.pgp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Date;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -24,14 +34,19 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpSignatureResult;
-import org.robolectric.*;
+import org.robolectric.RobolectricGradleTestRunner;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
+import org.spongycastle.bcpg.BCPGInputStream;
+import org.spongycastle.bcpg.Packet;
+import org.spongycastle.bcpg.PacketTags;
+import org.spongycastle.bcpg.PublicKeyEncSessionPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPEncryptedData;
-import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
+import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
@@ -39,21 +54,19 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
-import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
+import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
import org.sufficientlysecure.keychain.util.TestingUtils;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.security.Security;
-import java.util.HashSet;
+import static org.hamcrest.core.AnyOf.anyOf;
+import static org.hamcrest.core.Is.is;
+
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = WorkaroundBuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml")
@@ -83,6 +96,8 @@ public class PgpEncryptDecryptTest {
Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+ Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("bloom");
parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase1);
@@ -146,7 +161,8 @@ public class PgpEncryptDecryptTest {
b.setSymmetricPassphrase(mPassphrase);
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
- PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out);
+ PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(new Date()),
+ data, out);
Assert.assertTrue("encryption must succeed", result.success());
@@ -255,7 +271,8 @@ public class PgpEncryptDecryptTest {
input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() });
input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
- PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(), data, out);
+ PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(new Date()),
+ data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
@@ -327,6 +344,104 @@ public class PgpEncryptDecryptTest {
}
@Test
+ public void testAsymmetricMultiSubkeyEncrypt() throws Exception {
+
+ String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
+
+ { // encrypt data with key
+ byte[] ciphertext;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
+
+ PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+
+ InputData data = new InputData(in, in.available());
+ PgpSignEncryptInputParcel input = new PgpSignEncryptInputParcel();
+
+ input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() });
+ input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
+ PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(new Date()),
+ data, out);
+ Assert.assertTrue("encryption must succeed", result.success());
+
+ ciphertext = out.toByteArray();
+
+ Iterator<RawPacket> packets = KeyringTestingHelper.parseKeyring(ciphertext);
+
+ RawPacket enc1 = packets.next(), enc2 = packets.next();
+ Assert.assertEquals("last packet must be encrypted data packet",
+ PacketTags.SYM_ENC_INTEGRITY_PRO, packets.next().tag);
+ Assert.assertFalse("no further packets", packets.hasNext());
+
+ Packet p;
+ p = new BCPGInputStream(new ByteArrayInputStream(enc1.buf)).readPacket();
+ Assert.assertTrue("first packet must be session packet", p instanceof PublicKeyEncSessionPacket);
+ long encKeyId1 = ((PublicKeyEncSessionPacket) p).getKeyID();
+
+ p = new BCPGInputStream(new ByteArrayInputStream(enc2.buf)).readPacket();
+ Assert.assertTrue("second packet must be session packet", p instanceof PublicKeyEncSessionPacket);
+ long encKeyId2 = ((PublicKeyEncSessionPacket) p).getKeyID();
+
+ Assert.assertNotEquals("encrypted-to subkey ids must not be equal",
+ encKeyId1, encKeyId2);
+ Assert.assertThat("first packet must be encrypted to one of the subkeys",
+ KeyringTestingHelper.getSubkeyId(mStaticRing1, 2), anyOf(is(encKeyId1), is(encKeyId2)));
+ Assert.assertThat("second packet must be encrypted to one of the subkeys",
+ KeyringTestingHelper.getSubkeyId(mStaticRing1, 3), anyOf(is(encKeyId1), is(encKeyId2)));
+
+ }
+
+ { // revoke first encryption subkey of keyring in database
+ SaveKeyringParcel parcel = new SaveKeyringParcel(mStaticRing1.getMasterKeyId(), mStaticRing1.getFingerprint());
+ parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(mStaticRing1, 2));
+ UncachedKeyRing modified = PgpKeyOperationTest.applyModificationWithChecks(parcel, mStaticRing1,
+ new ArrayList<RawPacket>(), new ArrayList<RawPacket>(),
+ new CryptoInputParcel(new Date(), mKeyPhrase1));
+
+ ProviderHelper providerHelper = new ProviderHelper(RuntimeEnvironment.application);
+ providerHelper.saveSecretKeyRing(modified, new ProgressScaler());
+ }
+
+ { // encrypt to this keyring, make sure it's not encrypted to the revoked subkey
+ byte[] ciphertext;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
+
+ PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+
+ InputData data = new InputData(in, in.available());
+ PgpSignEncryptInputParcel input = new PgpSignEncryptInputParcel();
+
+ input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() });
+ input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
+ PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(new Date()),
+ data, out);
+ Assert.assertTrue("encryption must succeed", result.success());
+
+ ciphertext = out.toByteArray();
+
+ Iterator<RawPacket> packets = KeyringTestingHelper.parseKeyring(ciphertext);
+
+ RawPacket enc1 = packets.next();
+ Assert.assertEquals("last packet must be encrypted data packet",
+ PacketTags.SYM_ENC_INTEGRITY_PRO, packets.next().tag);
+ Assert.assertFalse("no further packets", packets.hasNext());
+
+ Packet p;
+ p = new BCPGInputStream(new ByteArrayInputStream(enc1.buf)).readPacket();
+ Assert.assertTrue("first packet must be session packet", p instanceof PublicKeyEncSessionPacket);
+ Assert.assertEquals("first packet must be encrypted to second enc subkey",
+ KeyringTestingHelper.getSubkeyId(mStaticRing1, 3), ((PublicKeyEncSessionPacket) p).getKeyID());
+
+ }
+
+ }
+
+ @Test
public void testMultiAsymmetricEncryptDecrypt() {
String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
@@ -348,7 +463,8 @@ public class PgpEncryptDecryptTest {
});
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
- PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out);
+ PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(new Date()),
+ data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
@@ -466,7 +582,8 @@ public class PgpEncryptDecryptTest {
b.setSignatureSubKeyId(KeyringTestingHelper.getSubkeyId(mStaticRing1, 1));
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
- PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(mKeyPhrase1), data, out);
+ PgpSignEncryptResult result = op.execute(b,
+ new CryptoInputParcel(new Date(), mKeyPhrase1), data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
@@ -546,7 +663,8 @@ public class PgpEncryptDecryptTest {
// this only works with ascii armored output!
b.setEnableAsciiArmorOutput(true);
b.setCharset("iso-2022-jp");
- PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out);
+ PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(new Date()),
+ data, out);
Assert.assertTrue("encryption must succeed", result.success());
ciphertext = out.toByteArray();
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index fcb458fbe..c0e28cd4b 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -94,11 +94,11 @@ public class PgpKeyOperationTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.DSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 2048, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -821,6 +821,15 @@ public class PgpKeyOperationTest {
Assert.assertEquals("new packet should have GNU_DUMMY protection mode stripped",
S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY, ((SecretKeyPacket) p).getS2K().getProtectionMode());
}
+
+ { // trying to edit a subkey with signing capability should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true));
+
+ assertModifyFailure("subkey modification for signing-enabled but stripped subkey should fail",
+ modified, parcel, LogType.MSG_MF_ERROR_SUB_STRIPPED);
+ }
+
}
@Test
@@ -829,7 +838,7 @@ public class PgpKeyOperationTest {
UncachedKeyRing modified;
{ // keytocard should fail with BAD_NFC_SIZE when presented with the RSA-1024 key
- long keyId = KeyringTestingHelper.getSubkeyId(ring, 0);
+ long keyId = KeyringTestingHelper.getSubkeyId(ring, 2);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
@@ -838,7 +847,7 @@ public class PgpKeyOperationTest {
}
{ // keytocard should fail with BAD_NFC_ALGO when presented with the DSA-1024 key
- long keyId = KeyringTestingHelper.getSubkeyId(ring, 1);
+ long keyId = KeyringTestingHelper.getSubkeyId(ring, 0);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
@@ -846,9 +855,10 @@ public class PgpKeyOperationTest {
parcel, cryptoInput, LogType.MSG_MF_ERROR_BAD_NFC_ALGO);
}
+ long keyId = KeyringTestingHelper.getSubkeyId(ring, 1);
+
{ // keytocard should return a pending NFC_MOVE_KEY_TO_CARD result when presented with the RSA-2048
// key, and then make key divert-to-card when it gets a serial in the cryptoInputParcel.
- long keyId = KeyringTestingHelper.getSubkeyId(ring, 2);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
@@ -880,7 +890,19 @@ public class PgpKeyOperationTest {
S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD, ((SecretKeyPacket) p).getS2K().getProtectionMode());
Assert.assertArrayEquals("new packet should have correct serial number as iv",
serial, ((SecretKeyPacket) p).getIV());
+ }
+
+ { // editing a signing subkey requires a primary key binding sig -> pendinginput
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true));
+ CanonicalizedSecretKeyRing secretRing =
+ new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
+ Assert.assertTrue("keytocard operation should be pending", result.isPending());
+ Assert.assertEquals("required input should be RequiredInputType.NFC_SIGN",
+ RequiredInputType.NFC_SIGN, result.getRequiredInputParcel().mType);
}
}
@@ -1240,14 +1262,14 @@ public class PgpKeyOperationTest {
Assert.assertFalse("non-restricted operations should fail without passphrase", result.success());
}
- private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
+ public static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB) {
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, cryptoInput, true, true);
}
- private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
+ public static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB,
@@ -1256,7 +1278,7 @@ public class PgpKeyOperationTest {
}
// applies a parcel modification while running some integrity checks
- private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
+ public static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
UncachedKeyRing ring,
ArrayList<RawPacket> onlyA,
ArrayList<RawPacket> onlyB,
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
index 0143ae289..a0f3b6be6 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -554,12 +554,13 @@ public class UncachedKeyringCanonicalizeTest {
CanonicalizedSecretKey masterSecretKey = canonicalized.getSecretKey();
masterSecretKey.unlock(new Passphrase());
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
- CryptoInputParcel cryptoInput = new CryptoInputParcel();
+ CryptoInputParcel cryptoInput = new CryptoInputParcel(new Date());
PGPSignature cert = PgpKeyOperation.generateSubkeyBindingSignature(
PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), cryptoInput),
cryptoInput.getSignatureTime(),
- masterPublicKey, masterSecretKey.getPrivateKey(), masterSecretKey.getPrivateKey(),
- masterPublicKey, masterSecretKey.getKeyUsage(), 0);
+ masterPublicKey, masterSecretKey.getPrivateKey(),
+ PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), null),
+ masterSecretKey.getPrivateKey(), masterPublicKey, masterSecretKey.getKeyUsage(), 0);
PGPPublicKey subPubKey = PGPPublicKey.addSubkeyBindingCertification(masterPublicKey, cert);
PGPSecretKey sKey;
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
index cc5c487bd..6755431d0 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
@@ -194,11 +194,11 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddUserIds.add("flim");
- modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
+ modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
parcel.reset();
parcel.mAddUserIds.add("flam");
- modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
+ modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
}
{ // merge A into base
@@ -235,8 +235,8 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
- modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
- modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
+ modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
+ modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
subKeyIdA = KeyringTestingHelper.getSubkeyId(modifiedA, 2);
subKeyIdB = KeyringTestingHelper.getSubkeyId(modifiedB, 2);
@@ -277,7 +277,7 @@ public class UncachedKeyringMergeTest {
parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(ringA, 1));
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
+ modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
}
{
@@ -376,7 +376,7 @@ public class UncachedKeyringMergeTest {
CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing(
ringA.getEncoded(), false, 0);
- modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing();
+ modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
}
{
diff --git a/extern/KeybaseLib b/extern/KeybaseLib
-Subproject 9615d90b18d1aee4dad994aa45875adfdcfb3c3
+Subproject 0b0a60533c5f76b60e43895f3a0342bb0be6853
diff --git a/extern/safeslinger-exchange b/extern/safeslinger-exchange
-Subproject 7c84cb54df5b3d5c6780984e48f3e9e4cbc5128
+Subproject ca3300ac9bac73df2124301f5024db309a03c29
diff --git a/extern/snackbar b/extern/snackbar
new file mode 160000
+Subproject abd5c3eb4773e9f4454c22c204419b5f33096e9
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 49cf64134..ef73025c0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
-#Mon Mar 23 19:39:48 CET 2015
+#Mon Aug 03 18:56:28 CEST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-bin.zip
-distributionSha256Sum=c4eaecc621a81f567ded1aede4a5ddb281cc02a03a6a87c4f5502add8fc2f16f \ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
+distributionSha256Sum=371cb9fbebbe9880d147f59bab36d61eee122854ef8c9ee1ecf12b82368bcf10 \ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index baf7e0e64..ec35f094e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -7,4 +7,5 @@ include ':extern:spongycastle:pkix'
include ':extern:spongycastle:prov'
include ':extern:minidns'
include ':extern:KeybaseLib:Lib'
-include ':extern:safeslinger-exchange'
+include ':extern:safeslinger-exchange:safeslinger-exchange'
+include ':extern:snackbar:lib'
diff --git a/tools/checkstyle b/tools/checkstyle
index 27aabced2..0f6d142c8 100755
--- a/tools/checkstyle
+++ b/tools/checkstyle
@@ -1 +1 @@
-checkstyle -c tools/checkstyle.xml -r OpenPGP-Keychain/src/main/java 2>&1 | egrep -v 'log4j'
+checkstyle -c tools/checkstyle.xml -r OpenKeychain/src/main/java 2>&1 | egrep -v 'log4j'