aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src')
-rw-r--r--OpenPGP-Keychain/src/main/AndroidManifest.xml82
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java26
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java1
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java1
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java5
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java62
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java41
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java102
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java37
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java19
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java55
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java38
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java199
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java37
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java50
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java138
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java246
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java226
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java256
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java129
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java19
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java19
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java78
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java54
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java239
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java3
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java1
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java42
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java226
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AccountSettings.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettings.java)61
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java54
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java)83
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java)107
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/WrongPackageSignatureException.java27
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java)65
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java176
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java200
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java138
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java108
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java)7
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java)94
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java)91
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java232
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java86
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java57
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java243
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsAdapter.java76
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java163
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java65
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java175
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java112
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java72
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java13
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java31
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java13
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java94
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java9
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java12
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java66
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java6
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java84
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java14
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java)60
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java686
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java71
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java382
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java238
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java101
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java26
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java20
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java177
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java95
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java39
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java161
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java24
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java45
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java17
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java4
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java132
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java17
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java65
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java94
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java198
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java67
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java25
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java233
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java138
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java31
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java31
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java69
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java88
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java1
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java46
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java27
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java194
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java50
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java60
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java29
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java26
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java7
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java3
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java4
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java203
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java37
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java4
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java126
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java68
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java7
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java219
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java12
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java16
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java18
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java1
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java51
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java50
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java252
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java12
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_person.pngbin0 -> 573 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_save.pngbin0 -> 398 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-hdpi/icon.pngbin5101 -> 5093 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-hdpi/revoked_key_small.pngbin0 -> 2509 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-ldpi/icon.pngbin1969 -> 1967 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_person.pngbin0 -> 468 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_save.pngbin0 -> 359 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-mdpi/icon.pngbin2906 -> 2896 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_person.pngbin0 -> 781 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_save.pngbin0 -> 451 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-xhdpi/icon.pngbin7895 -> 7870 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_person.pngbin0 -> 1004 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_save.pngbin0 -> 500 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-xxhdpi/icon.pngbin14188 -> 14153 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable-xxxhdpi/icon.pngbin20919 -> 20825 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable/revoked_key_small.pngbin0 -> 1793 bytes
-rw-r--r--OpenPGP-Keychain/src/main/res/drawable/selector_transparent_button.xml7
-rw-r--r--OpenPGP-Keychain/src/main/res/layout-large/api_apps_list_activity.xml20
-rw-r--r--OpenPGP-Keychain/src/main/res/layout-large/decrypt_activity.xml19
-rw-r--r--OpenPGP-Keychain/src/main/res/layout-large/encrypt_activity.xml19
-rw-r--r--OpenPGP-Keychain/src/main/res/layout-large/import_keys_activity.xml21
-rw-r--r--OpenPGP-Keychain/src/main/res/layout-large/key_list_activity.xml18
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_account_settings_activity.xml20
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_account_settings_fragment.xml102
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_accounts_adapter_list_item.xml27
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml16
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml68
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_apps_list_activity.xml11
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_apps_list_content.xml14
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_remote_create_account.xml29
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_remote_error_message.xml (renamed from OpenPGP-Keychain/src/main/res/layout/api_app_error_message.xml)1
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_remote_register_app.xml (renamed from OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml)2
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/api_remote_select_pub_keys.xml (renamed from OpenPGP-Keychain/src/main/res/layout/api_app_select_pub_keys_activity.xml)1
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml87
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/create_key_dialog.xml7
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml203
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/decrypt_content.xml205
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/drawer_list.xml4
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/edit_key_key_item.xml2
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml5
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml342
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/encrypt_content.xml318
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/encrypt_content_adv_settings.xml63
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/file_dialog.xml4
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/foldable_linearlayout.xml41
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/import_keys_activity.xml53
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/import_keys_content.xml56
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml32
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_activity.xml11
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_content.xml14
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_fragment.xml109
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_header.xml30
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_item.xml78
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_public_activity.xml20
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_public_fragment.xml77
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_public_header.xml16
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml45
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml24
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml32
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml2
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_server_export.xml1
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml2
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml8
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/select_key_item.xml2
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml8
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/select_secret_key_layout_fragment.xml41
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_delete_fragment.xml38
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml64
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml49
-rw-r--r--OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml39
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/api_account_settings.xml14
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/key_list.xml38
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/key_list_multi.xml (renamed from OpenPGP-Keychain/src/main/res/menu/key_list_public_multi.xml)12
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/key_list_public.xml20
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/key_list_secret.xml22
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml13
-rw-r--r--OpenPGP-Keychain/src/main/res/menu/key_view.xml4
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_about.html49
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_changelog.html129
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-cs-rCZ/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html33
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-de/help_start.html6
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-el/help_about.html49
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-el/help_changelog.html129
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-el/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-el/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-el/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-es/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-et/help_about.html49
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-et/help_changelog.html129
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-et/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-et/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-et/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_about.html49
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_changelog.html129
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fa-rIR/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-fr/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ja/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pl/help_about.html49
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pl/help_changelog.html129
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pl/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pl/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pl/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ru/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-ru/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-tr/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-uk/help_about.html14
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-uk/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_about.html49
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_changelog.html129
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_nfc_beam.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_start.html19
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh-rTW/nfc_beam_share.html11
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_about.html20
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html21
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html10
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/help_start.html12
-rw-r--r--OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html8
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_about.html15
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_changelog.html23
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_faq.html13
-rw-r--r--OpenPGP-Keychain/src/main/res/raw/help_start.html2
-rw-r--r--OpenPGP-Keychain/src/main/res/values-cs-rCZ/strings.xml49
-rw-r--r--OpenPGP-Keychain/src/main/res/values-de/strings.xml59
-rw-r--r--OpenPGP-Keychain/src/main/res/values-el/strings.xml54
-rw-r--r--OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml4
-rw-r--r--OpenPGP-Keychain/src/main/res/values-es/strings.xml128
-rw-r--r--OpenPGP-Keychain/src/main/res/values-et/strings.xml123
-rw-r--r--OpenPGP-Keychain/src/main/res/values-fa-rIR/strings.xml27
-rw-r--r--OpenPGP-Keychain/src/main/res/values-fr/strings.xml130
-rw-r--r--OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml124
-rw-r--r--OpenPGP-Keychain/src/main/res/values-ja/strings.xml117
-rw-r--r--OpenPGP-Keychain/src/main/res/values-large/dimens.xml4
-rw-r--r--OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml57
-rw-r--r--OpenPGP-Keychain/src/main/res/values-pl/strings.xml457
-rw-r--r--OpenPGP-Keychain/src/main/res/values-pt-rBR/strings.xml1
-rw-r--r--OpenPGP-Keychain/src/main/res/values-ru/strings.xml123
-rw-r--r--OpenPGP-Keychain/src/main/res/values-sl-rSI/strings.xml1
-rw-r--r--OpenPGP-Keychain/src/main/res/values-tr/strings.xml26
-rw-r--r--OpenPGP-Keychain/src/main/res/values-uk/strings.xml57
-rw-r--r--OpenPGP-Keychain/src/main/res/values-zh-rTW/strings.xml27
-rw-r--r--OpenPGP-Keychain/src/main/res/values-zh/strings.xml48
-rw-r--r--OpenPGP-Keychain/src/main/res/values/arrays.xml2
-rw-r--r--OpenPGP-Keychain/src/main/res/values/attr.xml11
-rw-r--r--OpenPGP-Keychain/src/main/res/values/colors.xml2
-rw-r--r--OpenPGP-Keychain/src/main/res/values/dimens.xml5
-rw-r--r--OpenPGP-Keychain/src/main/res/values/strings.xml59
301 files changed, 10717 insertions, 5692 deletions
diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml
index 8aa37393f..10505248f 100644
--- a/OpenPGP-Keychain/src/main/AndroidManifest.xml
+++ b/OpenPGP-Keychain/src/main/AndroidManifest.xml
@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sufficientlysecure.keychain"
android:installLocation="auto"
- android:versionCode="23103"
- android:versionName="2.3.1 beta3">
+ android:versionCode="24000"
+ android:versionName="2.4">
<!--
General remarks
@@ -50,6 +50,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.NFC" />
+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->
<application
@@ -60,7 +61,7 @@
android:theme="@style/KeychainTheme"
android:label="@string/app_name">
<activity
- android:name=".ui.KeyListPublicActivity"
+ android:name=".ui.KeyListActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/app_name"
android:launchMode="singleTop">
@@ -71,12 +72,6 @@
</intent-filter>
</activity>
<activity
- android:name=".ui.KeyListSecretActivity"
- android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
- android:label="@string/title_manage_secret_keys"
- android:launchMode="singleTop">
- </activity>
- <activity
android:name=".ui.EditKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_edit_key"
@@ -85,32 +80,30 @@
android:name=".ui.ViewKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_key_details"
- android:parentActivityName=".ui.KeyListPublicActivity">
+ android:parentActivityName=".ui.KeyListActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
- android:value=".ui.KeyListPublicActivity" />
+ android:value=".ui.KeyListActivity" />
</activity>
<activity
android:name=".ui.ViewKeyActivityJB"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_key_details"
- android:parentActivityName=".ui.KeyListPublicActivity">
+ android:parentActivityName=".ui.KeyListActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
- android:value=".ui.KeyListPublicActivity" />
+ android:value=".ui.KeyListActivity" />
</activity>
<activity
android:name=".ui.SelectPublicKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_select_recipients"
- android:launchMode="singleTop">
- </activity>
+ android:launchMode="singleTop"></activity>
<activity
android:name=".ui.SelectSecretKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_select_secret_key"
- android:launchMode="singleTop">
- </activity>
+ android:launchMode="singleTop"></activity>
<activity
android:name=".ui.EncryptActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
@@ -149,23 +142,23 @@
<!--&lt;!&ndash; VIEW with mimeType: TODO (from email app) &ndash;&gt;-->
<!--<intent-filter android:label="@string/intent_import_key">-->
- <!--<action android:name="android.intent.action.VIEW" />-->
+ <!--<action android:name="android.intent.action.VIEW" />-->
- <!--<category android:name="android.intent.category.BROWSABLE" />-->
- <!--<category android:name="android.intent.category.DEFAULT" />-->
+ <!--<category android:name="android.intent.category.BROWSABLE" />-->
+ <!--<category android:name="android.intent.category.DEFAULT" />-->
- <!--&lt;!&ndash; mime type as defined in http://tools.ietf.org/html/rfc3156 &ndash;&gt;-->
- <!--<data android:mimeType="application/pgp-signature" />-->
+ <!--&lt;!&ndash; mime type as defined in http://tools.ietf.org/html/rfc3156 &ndash;&gt;-->
+ <!--<data android:mimeType="application/pgp-signature" />-->
<!--</intent-filter>-->
<!--&lt;!&ndash; VIEW with mimeType: TODO (from email app) &ndash;&gt;-->
<!--<intent-filter android:label="@string/intent_import_key">-->
- <!--<action android:name="android.intent.action.VIEW" />-->
+ <!--<action android:name="android.intent.action.VIEW" />-->
- <!--<category android:name="android.intent.category.BROWSABLE" />-->
- <!--<category android:name="android.intent.category.DEFAULT" />-->
+ <!--<category android:name="android.intent.category.BROWSABLE" />-->
+ <!--<category android:name="android.intent.category.DEFAULT" />-->
- <!--&lt;!&ndash; mime type as defined in http://tools.ietf.org/html/rfc3156 &ndash;&gt;-->
- <!--<data android:mimeType="application/pgp-encrypted" />-->
+ <!--&lt;!&ndash; mime type as defined in http://tools.ietf.org/html/rfc3156 &ndash;&gt;-->
+ <!--<data android:mimeType="application/pgp-encrypted" />-->
<!--</intent-filter>-->
<!-- Keychain's own Actions -->
<!-- DECRYPT with text as extra -->
@@ -241,7 +234,7 @@
<activity
android:name=".ui.PreferencesActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
- android:label="@string/title_preferences" >
+ android:label="@string/title_preferences">
<intent-filter>
<action android:name="org.sufficientlysecure.keychain.ui.PREFS_GEN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -379,44 +372,49 @@
android:exported="false"
android:process=":passphrase_cache" />
<service
- android:name="org.sufficientlysecure.keychain.service.KeychainIntentService"
+ android:name=".service.KeychainIntentService"
android:exported="false" />
<provider
- android:name="org.sufficientlysecure.keychain.provider.KeychainProvider"
+ android:name=".provider.KeychainProvider"
android:authorities="org.sufficientlysecure.keychain.provider"
android:exported="false" />
<!-- Internal classes of the remote APIs (not exported) -->
<activity
- android:name="org.sufficientlysecure.keychain.service.remote.RemoteServiceActivity"
+ android:name=".remote.ui.RemoteServiceActivity"
android:exported="false"
- android:label="@string/app_name" />
- <!--android:launchMode="singleTop"-->
- <!--android:process=":remote_api"-->
+ android:label="@string/app_name"
+ android:launchMode="singleTop"
+ android:process=":remote_api" />
<activity
- android:name="org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity"
+ android:name=".remote.ui.AppsListActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:exported="false"
android:label="@string/title_api_registered_apps" />
<activity
- android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsActivity"
+ android:name=".remote.ui.AppSettingsActivity"
+ android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
+ android:exported="false">
+
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".remote.ui.AppsListActivity" />
+ </activity>
+ <activity
+ android:name=".remote.ui.AccountSettingsActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:exported="false" />
<!-- OpenPGP Remote API -->
<service
- android:name="org.sufficientlysecure.keychain.service.remote.OpenPgpService"
+ android:name=".remote.OpenPgpService"
android:enabled="true"
android:exported="true"
android:process=":remote_api">
<intent-filter>
<action android:name="org.openintents.openpgp.IOpenPgpService" />
</intent-filter>
-
- <meta-data
- android:name="api_version"
- android:value="1" />
</service>
<!-- Extended Remote API -->
@@ -437,4 +435,4 @@
<!-- android:permission="org.sufficientlysecure.keychain.permission.ACCESS_API" /> -->
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 4428c7133..f9a7962ec 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -16,10 +16,15 @@
package org.sufficientlysecure.keychain;
-import org.spongycastle.jce.provider.BouncyCastleProvider;
-
import android.os.Environment;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.sufficientlysecure.keychain.remote.ui.AppsListActivity;
+import org.sufficientlysecure.keychain.ui.DecryptActivity;
+import org.sufficientlysecure.keychain.ui.EncryptActivity;
+import org.sufficientlysecure.keychain.ui.ImportKeysActivity;
+import org.sufficientlysecure.keychain.ui.KeyListActivity;
+
public final class Constants {
public static final boolean DEBUG = BuildConfig.DEBUG;
@@ -40,12 +45,14 @@ public final class Constants {
public static final String INTENT_PREFIX = PACKAGE_NAME + ".action.";
- public static final class path {
+ public static final class Path {
public static final String APP_DIR = Environment.getExternalStorageDirectory()
+ "/OpenPGP-Keychain";
+ public static final String APP_DIR_FILE_SEC = APP_DIR + "/secexport.asc";
+ public static final String APP_DIR_FILE_PUB = APP_DIR + "/pubexport.asc";
}
- public static final class pref {
+ public static final class Pref {
public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm";
public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm";
public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour";
@@ -57,8 +64,17 @@ public final class Constants {
public static final String KEY_SERVERS = "keyServers";
}
- public static final class defaults {
+ public static final class Defaults {
public static final String KEY_SERVERS = "pool.sks-keyservers.net, subkeys.pgp.net, pgp.mit.edu";
}
+ public static final class DrawerItems {
+ public static final Class KEY_LIST = KeyListActivity.class;
+ public static final Class ENCRYPT = EncryptActivity.class;
+ public static final Class DECRYPT = DecryptActivity.class;
+ public static final Class IMPORT_KEYS = ImportKeysActivity.class;
+ public static final Class REGISTERED_APPS_LIST = AppsListActivity.class;
+ public static final Class[] ARRAY = new Class[]{KEY_LIST, ENCRYPT, DECRYPT,
+ IMPORT_KEYS, REGISTERED_APPS_LIST};
+ }
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java
index 1d79edd43..784ec340e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java
@@ -119,6 +119,7 @@ public final class Id {
public static final int secret_key = 0x21070002;
public static final int user_id = 0x21070003;
public static final int key = 0x21070004;
+ public static final int public_secret_key = 0x21070005;
}
public static final class choice {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 4a25f2df1..98b827542 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -64,7 +64,7 @@ public class KeychainApplication extends Application {
// Create APG directory on sdcard if not existing
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- File dir = new File(Constants.path.APP_DIR);
+ File dir = new File(Constants.Path.APP_DIR);
if (!dir.exists() && !dir.mkdirs()) {
// ignore this for now, it's not crucial
// that the directory doesn't exist at this point
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
index 032af4c71..3164de7d1 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
@@ -59,7 +59,6 @@ public class ClipboardReflection {
* Wrapper around ClipboardManager based on Android version using Reflection API
*
* @param context
- * @param text
*/
public static CharSequence getClipboardText(Context context) {
Object clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
index a209f16cf..36f7fd23b 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
@@ -37,8 +37,9 @@ import android.os.Handler;
* </code>
*/
public class DialogFragmentWorkaround {
- public static final SDKLevel17Interface INTERFACE = ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ? new SDKLevel17Impl()
- : new SDKLevelPriorLevel17Impl());
+ public static final SDKLevel17Interface INTERFACE =
+ ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ? new SDKLevel17Impl()
+ : new SDKLevelPriorLevel17Impl());
private static final int RUNNABLE_DELAY = 300;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java
index b55075e6c..a26df556d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java
@@ -17,28 +17,26 @@
package org.sufficientlysecure.keychain.helper;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.Activity;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.TextView;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
public class ActionBarHelper {
/**
* Set actionbar without home button if called from another app
- *
+ *
* @param activity
*/
public static void setBackButton(ActionBarActivity activity) {
- // set actionbar without home button if called from another app
final ActionBar actionBar = activity.getSupportActionBar();
Log.d(Constants.TAG, "calling package (only set when using startActivityForResult)="
+ activity.getCallingPackage());
@@ -54,30 +52,35 @@ public class ActionBarHelper {
/**
* Sets custom view on ActionBar for Done/Cancel activities
- *
+ *
* @param actionBar
- * @param doneText
- * @param doneOnClickListener
- * @param cancelText
- * @param cancelOnClickListener
+ * @param firstText
+ * @param firstDrawableId
+ * @param firstOnClickListener
+ * @param secondText
+ * @param secondDrawableId
+ * @param secondOnClickListener
*/
- public static void setDoneCancelView(ActionBar actionBar, int doneText,
- OnClickListener doneOnClickListener, int cancelText,
- OnClickListener cancelOnClickListener) {
+ public static void setTwoButtonView(ActionBar actionBar,
+ int firstText, int firstDrawableId, OnClickListener firstOnClickListener,
+ int secondText, int secondDrawableId, OnClickListener secondOnClickListener) {
- // Inflate a "Done"/"Cancel" custom action bar view
+ // Inflate the custom action bar view
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater.inflate(
R.layout.actionbar_custom_view_done_cancel, null);
- ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)).setText(doneText);
+ TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text));
+ firstTextView.setText(firstText);
+ firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0);
customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener(
- doneOnClickListener);
- ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text))
- .setText(cancelText);
+ firstOnClickListener);
+ TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text));
+ secondTextView.setText(secondText);
+ secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0);
customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener(
- cancelOnClickListener);
+ secondOnClickListener);
// Show the custom action bar view and hide the normal Home icon and title.
actionBar.setDisplayShowTitleEnabled(false);
@@ -89,22 +92,24 @@ public class ActionBarHelper {
/**
* Sets custom view on ActionBar for Done activities
- *
+ *
* @param actionBar
- * @param doneText
- * @param doneOnClickListener
+ * @param firstText
+ * @param firstOnClickListener
*/
- public static void setDoneView(ActionBar actionBar, int doneText,
- OnClickListener doneOnClickListener) {
+ public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId,
+ OnClickListener firstOnClickListener) {
// Inflate a "Done" custom action bar view to serve as the "Up" affordance.
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater
.inflate(R.layout.actionbar_custom_view_done, null);
- ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)).setText(doneText);
+ TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text));
+ firstTextView.setText(firstText);
+ firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0);
customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener(
- doneOnClickListener);
+ firstOnClickListener);
// Show the custom action bar view and hide the normal Home icon and title.
actionBar.setDisplayShowTitleEnabled(false);
@@ -112,5 +117,4 @@ public class ActionBarHelper {
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(customActionBarView);
}
-
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
new file mode 100644
index 000000000..f8ed21816
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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.helper;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.Context;
+import android.util.Patterns;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class ContactHelper {
+
+ public static final List<String> getMailAccounts(Context context) {
+ final Account[] accounts = AccountManager.get(context).getAccounts();
+ final Set<String> emailSet = new HashSet<String>();
+ for (Account account : accounts) {
+ if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
+ emailSet.add(account.name);
+ }
+ }
+ return new ArrayList<String>(emailSet);
+ }
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
index 21676a2a7..cc240a67b 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
@@ -16,10 +16,21 @@
package org.sufficientlysecure.keychain.helper;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v7.app.ActionBarActivity;
+import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
@@ -27,44 +38,38 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.support.v7.app.ActionBarActivity;
-import android.widget.Toast;
+import java.lang.reflect.Array;
+import java.security.Provider;
+import java.util.ArrayList;
public class ExportHelper {
protected FileDialogFragment mFileDialog;
protected String mExportFilename;
- ActionBarActivity activity;
+ ActionBarActivity mActivity;
public ExportHelper(ActionBarActivity activity) {
super();
- this.activity = activity;
+ this.mActivity = activity;
}
- public void deleteKey(Uri dataUri, final int keyType, Handler deleteHandler) {
+ public void deleteKey(Uri dataUri, Handler deleteHandler) {
long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment());
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(deleteHandler);
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
- new long[] { keyRingRowId }, keyType);
+ new long[]{keyRingRowId});
- deleteKeyDialog.show(activity.getSupportFragmentManager(), "deleteKeyDialog");
+ deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog");
}
/**
* Show dialog where to export keys
*/
- public void showExportKeysDialog(final Uri dataUri, final int keyType,
- final String exportFilename) {
+ public void showExportKeysDialog(final long[] masterKeyIds, final int keyType,
+ final String exportFilename, final String checkboxString) {
mExportFilename = exportFilename;
// Message is received after file is selected
@@ -73,9 +78,14 @@ public class ExportHelper {
public void handleMessage(Message message) {
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
Bundle data = message.getData();
+ int type = keyType;
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
- exportKeys(dataUri, keyType);
+ if( data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED) ) {
+ type = Id.type.public_secret_key;
+ }
+
+ exportKeys(masterKeyIds, type);
}
}
};
@@ -86,25 +96,20 @@ public class ExportHelper {
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
public void run() {
String title = null;
- if (dataUri == null) {
+ if (masterKeyIds == null) {
// export all keys
- title = activity.getString(R.string.title_export_keys);
+ title = mActivity.getString(R.string.title_export_keys);
} else {
// export only key specified at data uri
- title = activity.getString(R.string.title_export_key);
+ title = mActivity.getString(R.string.title_export_key);
}
- String message = null;
- if (keyType == Id.type.public_key) {
- message = activity.getString(R.string.specify_file_to_export_to);
- } else {
- message = activity.getString(R.string.specify_file_to_export_secret_keys_to);
- }
+ String message = mActivity.getString(R.string.specify_file_to_export_to);
mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
- exportFilename, null);
+ exportFilename, checkboxString);
- mFileDialog.show(activity.getSupportFragmentManager(), "fileDialog");
+ mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
}
});
}
@@ -112,11 +117,11 @@ public class ExportHelper {
/**
* Export keys
*/
- public void exportKeys(Uri dataUri, int keyType) {
+ public void exportKeys(long[] masterKeyIds, int keyType) {
Log.d(Constants.TAG, "exportKeys started");
// Send all information needed to service to export key in other thread
- Intent intent = new Intent(activity, KeychainIntentService.class);
+ final Intent intent = new Intent(mActivity, KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING);
@@ -126,22 +131,27 @@ public class ExportHelper {
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType);
- if (dataUri == null) {
+ if (masterKeyIds == null) {
data.putBoolean(KeychainIntentService.EXPORT_ALL, true);
} else {
- // TODO: put data uri into service???
- long keyRingMasterKeyId = ProviderHelper.getMasterKeyId(activity, dataUri);
-
- data.putLong(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, keyRingMasterKeyId);
+ data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, masterKeyIds);
}
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after exporting is done in ApgService
- KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(activity,
- R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) {
+ // Message is received after exporting is done in KeychainIntentService
+ KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity,
+ mActivity.getString(R.string.progress_exporting),
+ ProgressDialog.STYLE_HORIZONTAL,
+ true,
+ new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialogInterface) {
+ mActivity.stopService(intent);
+ }
+ }) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -151,16 +161,16 @@ public class ExportHelper {
int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT);
String toastMessage;
if (exported == 1) {
- toastMessage = activity.getString(R.string.key_exported);
+ toastMessage = mActivity.getString(R.string.key_exported);
} else if (exported > 0) {
- toastMessage = activity.getString(R.string.keys_exported, exported);
+ toastMessage = mActivity.getString(R.string.keys_exported, exported);
} else {
- toastMessage = activity.getString(R.string.no_keys_exported);
+ toastMessage = mActivity.getString(R.string.no_keys_exported);
}
- Toast.makeText(activity, toastMessage, Toast.LENGTH_SHORT).show();
+ Toast.makeText(mActivity, toastMessage, Toast.LENGTH_SHORT).show();
}
- };
+ }
};
// Create a new Messenger for the communication back
@@ -168,10 +178,10 @@ public class ExportHelper {
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
// show progress dialog
- exportHandler.showProgressDialog(activity);
+ exportHandler.showProgressDialog(mActivity);
// start service with intent
- activity.startService(intent);
+ mActivity.startService(intent);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java
index ec56fe912..d24aeca52 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java
@@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.helper;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -30,12 +26,15 @@ import android.net.Uri;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.widget.Toast;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
public class FileHelper {
/**
* Checks if external storage is mounted if file is located on external storage
- *
+ *
* @param file
* @return true if storage is mounted
*/
@@ -52,15 +51,12 @@ public class FileHelper {
/**
* Opens the preferred installed file manager on Android and shows a toast if no manager is
* installed.
- *
+ *
* @param activity
- * @param filename
- * default selected file, not supported by all file managers
- * @param mimeType
- * can be text/plain for example
- * @param requestCode
- * requestCode used to identify the result coming back from file manager to
- * onActivityResult() in your activity
+ * @param filename default selected file, not supported by all file managers
+ * @param mimeType can be text/plain for example
+ * @param requestCode requestCode used to identify the result coming back from file manager to
+ * onActivityResult() in your activity
*/
public static void openFile(Activity activity, String filename, String mimeType, int requestCode) {
Intent intent = buildFileIntent(filename, mimeType);
@@ -97,14 +93,13 @@ public class FileHelper {
/**
* Get a file path from a Uri.
- *
+ * <p/>
* from https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/
* afilechooser/utils/FileUtils.java
- *
+ *
* @param context
* @param uri
* @return
- *
* @author paulburke
*/
public static String getPath(Context context, Uri uri) {
@@ -115,21 +110,19 @@ public class FileHelper {
+ uri.getPathSegments().toString());
if ("content".equalsIgnoreCase(uri.getScheme())) {
- String[] projection = { "_data" };
+ String[] projection = {"_data"};
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
- int column_index = cursor.getColumnIndexOrThrow("_data");
+ int columnIndex = cursor.getColumnIndexOrThrow("_data");
if (cursor.moveToFirst()) {
- return cursor.getString(column_index);
+ return cursor.getString(columnIndex);
}
} catch (Exception e) {
// Eat it
}
- }
-
- else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ } else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java
index 639ab17b8..b31a889f0 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java
@@ -17,21 +17,22 @@
package org.sufficientlysecure.keychain.helper;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.Iterator;
-import java.util.Set;
+import android.os.Bundle;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.StrikethroughSpan;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
-import android.os.Bundle;
+import java.util.Iterator;
+import java.util.Set;
public class OtherHelper {
/**
* Logs bundle content to debug for inspecting the content
- *
+ *
* @param bundle
* @param bundleName
*/
@@ -60,4 +61,10 @@ public class OtherHelper {
}
}
+ public static SpannableStringBuilder strikeOutText(CharSequence text) {
+ SpannableStringBuilder sb = new SpannableStringBuilder(text);
+ sb.setSpan(new StrikethroughSpan(), 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ return sb;
+ }
+
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index 493f25707..515201b92 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -17,14 +17,13 @@
package org.sufficientlysecure.keychain.helper;
+import android.content.Context;
+import android.content.SharedPreferences;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
-import android.content.Context;
-import android.content.SharedPreferences;
-
import java.util.Vector;
/**
@@ -38,8 +37,8 @@ public class Preferences {
return getPreferences(context, false);
}
- public static synchronized Preferences getPreferences(Context context, boolean force_new) {
- if (mPreferences == null || force_new) {
+ public static synchronized Preferences getPreferences(Context context, boolean forceNew) {
+ if (mPreferences == null || forceNew) {
mPreferences = new Preferences(context);
}
return mPreferences;
@@ -50,17 +49,17 @@ public class Preferences {
}
public String getLanguage() {
- return mSharedPreferences.getString(Constants.pref.LANGUAGE, "");
+ return mSharedPreferences.getString(Constants.Pref.LANGUAGE, "");
}
public void setLanguage(String value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putString(Constants.pref.LANGUAGE, value);
+ editor.putString(Constants.Pref.LANGUAGE, value);
editor.commit();
}
public long getPassPhraseCacheTtl() {
- int ttl = mSharedPreferences.getInt(Constants.pref.PASS_PHRASE_CACHE_TTL, 180);
+ int ttl = mSharedPreferences.getInt(Constants.Pref.PASS_PHRASE_CACHE_TTL, 180);
// fix the value if it was set to "never" in previous versions, which currently is not
// supported
if (ttl == 0) {
@@ -71,81 +70,81 @@ public class Preferences {
public void setPassPhraseCacheTtl(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.pref.PASS_PHRASE_CACHE_TTL, value);
+ editor.putInt(Constants.Pref.PASS_PHRASE_CACHE_TTL, value);
editor.commit();
}
public int getDefaultEncryptionAlgorithm() {
- return mSharedPreferences.getInt(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM,
+ return mSharedPreferences.getInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM,
PGPEncryptedData.AES_256);
}
public void setDefaultEncryptionAlgorithm(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM, value);
+ editor.putInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM, value);
editor.commit();
}
public int getDefaultHashAlgorithm() {
- return mSharedPreferences.getInt(Constants.pref.DEFAULT_HASH_ALGORITHM,
+ return mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM,
HashAlgorithmTags.SHA512);
}
public void setDefaultHashAlgorithm(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.pref.DEFAULT_HASH_ALGORITHM, value);
+ editor.putInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, value);
editor.commit();
}
public int getDefaultMessageCompression() {
- return mSharedPreferences.getInt(Constants.pref.DEFAULT_MESSAGE_COMPRESSION,
+ return mSharedPreferences.getInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION,
Id.choice.compression.zlib);
}
public void setDefaultMessageCompression(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.pref.DEFAULT_MESSAGE_COMPRESSION, value);
+ editor.putInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION, value);
editor.commit();
}
public int getDefaultFileCompression() {
- return mSharedPreferences.getInt(Constants.pref.DEFAULT_FILE_COMPRESSION,
+ return mSharedPreferences.getInt(Constants.Pref.DEFAULT_FILE_COMPRESSION,
Id.choice.compression.none);
}
public void setDefaultFileCompression(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putInt(Constants.pref.DEFAULT_FILE_COMPRESSION, value);
+ editor.putInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, value);
editor.commit();
}
public boolean getDefaultAsciiArmour() {
- return mSharedPreferences.getBoolean(Constants.pref.DEFAULT_ASCII_ARMOUR, false);
+ return mSharedPreferences.getBoolean(Constants.Pref.DEFAULT_ASCII_ARMOUR, false);
}
public void setDefaultAsciiArmour(boolean value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putBoolean(Constants.pref.DEFAULT_ASCII_ARMOUR, value);
+ editor.putBoolean(Constants.Pref.DEFAULT_ASCII_ARMOUR, value);
editor.commit();
}
public boolean getForceV3Signatures() {
- return mSharedPreferences.getBoolean(Constants.pref.FORCE_V3_SIGNATURES, false);
+ return mSharedPreferences.getBoolean(Constants.Pref.FORCE_V3_SIGNATURES, false);
}
public void setForceV3Signatures(boolean value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putBoolean(Constants.pref.FORCE_V3_SIGNATURES, value);
+ editor.putBoolean(Constants.Pref.FORCE_V3_SIGNATURES, value);
editor.commit();
}
public String[] getKeyServers() {
- String rawData = mSharedPreferences.getString(Constants.pref.KEY_SERVERS,
- Constants.defaults.KEY_SERVERS);
+ String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS,
+ Constants.Defaults.KEY_SERVERS);
Vector<String> servers = new Vector<String>();
String chunks[] = rawData.split(",");
- for (int i = 0; i < chunks.length; ++i) {
- String tmp = chunks[i].trim();
+ for (String c : chunks) {
+ String tmp = c.trim();
if (tmp.length() > 0) {
servers.add(tmp);
}
@@ -156,8 +155,8 @@ public class Preferences {
public void setKeyServers(String[] value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
String rawData = "";
- for (int i = 0; i < value.length; ++i) {
- String tmp = value[i].trim();
+ for (String v : value) {
+ String tmp = v.trim();
if (tmp.length() == 0) {
continue;
}
@@ -166,7 +165,7 @@ public class Preferences {
}
rawData += tmp;
}
- editor.putString(Constants.pref.KEY_SERVERS, rawData);
+ editor.putString(Constants.Pref.KEY_SERVERS, rawData);
editor.commit();
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
index c7dd7d647..1f8dec7a1 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
@@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.pgp;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -29,12 +24,17 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+
public class PgpConversionHelper {
/**
* Convert from byte[] to PGPKeyRing
- *
+ *
* @param keysBytes
* @return
*/
@@ -54,7 +54,7 @@ public class PgpConversionHelper {
/**
* Convert from byte[] to ArrayList<PGPSecretKey>
- *
+ *
* @param keysBytes
* @return
*/
@@ -90,10 +90,10 @@ public class PgpConversionHelper {
/**
* Convert from byte[] to PGPSecretKey
- *
+ * <p/>
* Singles keys are encoded as keyRings with one single key in it by Bouncy Castle
- *
- * @param keysBytes
+ *
+ * @param keyBytes
* @return
*/
public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) {
@@ -105,13 +105,13 @@ public class PgpConversionHelper {
Log.e(Constants.TAG, "Error while converting to PGPSecretKey!", e);
}
PGPSecretKey secKey = null;
- if(obj instanceof PGPSecretKey) {
- if ((secKey = (PGPSecretKey)obj ) == null) {
+ if (obj instanceof PGPSecretKey) {
+ if ((secKey = (PGPSecretKey) obj) == null) {
Log.e(Constants.TAG, "No keys given!");
}
- } else if(obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
+ } else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
PGPSecretKeyRing keyRing = null;
- if ((keyRing = (PGPSecretKeyRing)obj) == null) {
+ if ((keyRing = (PGPSecretKeyRing) obj) == null) {
Log.e(Constants.TAG, "No keys given!");
}
secKey = keyRing.getSecretKey();
@@ -122,7 +122,7 @@ public class PgpConversionHelper {
/**
* Convert from ArrayList<PGPSecretKey> to byte[]
- *
+ *
* @param keys
* @return
*/
@@ -141,8 +141,8 @@ public class PgpConversionHelper {
/**
* Convert from PGPSecretKey to byte[]
- *
- * @param keysBytes
+ *
+ * @param key
* @return
*/
public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) {
@@ -157,8 +157,8 @@ public class PgpConversionHelper {
/**
* Convert from PGPSecretKeyRing to byte[]
- *
- * @param keysBytes
+ *
+ * @param keyRing
* @return
*/
public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index ccd6ff8df..571729bc5 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -18,38 +18,16 @@
package org.sufficientlysecure.keychain.pgp;
import android.content.Context;
-
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.SignatureSubpacketTags;
-import org.spongycastle.openpgp.PGPCompressedData;
-import org.spongycastle.openpgp.PGPEncryptedData;
-import org.spongycastle.openpgp.PGPEncryptedDataList;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPLiteralData;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPOnePassSignature;
-import org.spongycastle.openpgp.PGPOnePassSignatureList;
-import org.spongycastle.openpgp.PGPPBEEncryptedData;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.openpgp.PGPSignatureList;
-import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.*;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
+import org.spongycastle.openpgp.operator.jcajce.*;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@@ -59,12 +37,7 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.*;
import java.security.SignatureException;
import java.util.Iterator;
@@ -72,57 +45,57 @@ import java.util.Iterator;
* This class uses a Builder pattern!
*/
public class PgpDecryptVerify {
- private Context context;
- private InputData data;
- private OutputStream outStream;
+ private Context mContext;
+ private InputData mData;
+ private OutputStream mOutStream;
- private ProgressDialogUpdater progressDialogUpdater;
- private boolean assumeSymmetric;
- private String passphrase;
- private long enforcedKeyId;
+ private ProgressDialogUpdater mProgressDialogUpdater;
+ private boolean mAssumeSymmetric;
+ private String mPassphrase;
+ private long mEnforcedKeyId;
private PgpDecryptVerify(Builder builder) {
// private Constructor can only be called from Builder
- this.context = builder.context;
- this.data = builder.data;
- this.outStream = builder.outStream;
-
- this.progressDialogUpdater = builder.progressDialogUpdater;
- this.assumeSymmetric = builder.assumeSymmetric;
- this.passphrase = builder.passphrase;
- this.enforcedKeyId = builder.enforcedKeyId;
+ this.mContext = builder.mContext;
+ this.mData = builder.mData;
+ this.mOutStream = builder.mOutStream;
+
+ this.mProgressDialogUpdater = builder.mProgressDialogUpdater;
+ this.mAssumeSymmetric = builder.mAssumeSymmetric;
+ this.mPassphrase = builder.mPassphrase;
+ this.mEnforcedKeyId = builder.mEnforcedKeyId;
}
public static class Builder {
// mandatory parameter
- private Context context;
- private InputData data;
- private OutputStream outStream;
+ private Context mContext;
+ private InputData mData;
+ private OutputStream mOutStream;
// optional
- private ProgressDialogUpdater progressDialogUpdater = null;
- private boolean assumeSymmetric = false;
- private String passphrase = "";
- private long enforcedKeyId = 0;
+ private ProgressDialogUpdater mProgressDialogUpdater = null;
+ private boolean mAssumeSymmetric = false;
+ private String mPassphrase = "";
+ private long mEnforcedKeyId = 0;
public Builder(Context context, InputData data, OutputStream outStream) {
- this.context = context;
- this.data = data;
- this.outStream = outStream;
+ this.mContext = context;
+ this.mData = data;
+ this.mOutStream = outStream;
}
public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) {
- this.progressDialogUpdater = progressDialogUpdater;
+ this.mProgressDialogUpdater = progressDialogUpdater;
return this;
}
public Builder assumeSymmetric(boolean assumeSymmetric) {
- this.assumeSymmetric = assumeSymmetric;
+ this.mAssumeSymmetric = assumeSymmetric;
return this;
}
public Builder passphrase(String passphrase) {
- this.passphrase = passphrase;
+ this.mPassphrase = passphrase;
return this;
}
@@ -134,7 +107,7 @@ public class PgpDecryptVerify {
* @return
*/
public Builder enforcedKeyId(long enforcedKeyId) {
- this.enforcedKeyId = enforcedKeyId;
+ this.mEnforcedKeyId = enforcedKeyId;
return this;
}
@@ -144,14 +117,14 @@ public class PgpDecryptVerify {
}
public void updateProgress(int message, int current, int total) {
- if (progressDialogUpdater != null) {
- progressDialogUpdater.setProgress(message, current, total);
+ if (mProgressDialogUpdater != null) {
+ mProgressDialogUpdater.setProgress(message, current, total);
}
}
public void updateProgress(int current, int total) {
- if (progressDialogUpdater != null) {
- progressDialogUpdater.setProgress(current, total);
+ if (mProgressDialogUpdater != null) {
+ mProgressDialogUpdater.setProgress(current, total);
}
}
@@ -196,7 +169,7 @@ public class PgpDecryptVerify {
public PgpDecryptVerifyResult execute()
throws IOException, PgpGeneralException, PGPException, SignatureException {
// automatically works with ascii armor input and binary
- InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
+ InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
if (in instanceof ArmoredInputStream) {
ArmoredInputStream aIn = (ArmoredInputStream) in;
// it is ascii armored
@@ -240,7 +213,7 @@ public class PgpDecryptVerify {
}
if (enc == null) {
- throw new PgpGeneralException(context.getString(R.string.error_invalid_data));
+ throw new PgpGeneralException(mContext.getString(R.string.error_invalid_data));
}
InputStream clear;
@@ -250,7 +223,7 @@ public class PgpDecryptVerify {
// TODO: currently we always only look at the first known key or symmetric encryption,
// there might be more...
- if (assumeSymmetric) {
+ if (mAssumeSymmetric) {
PGPPBEEncryptedData pbe = null;
Iterator<?> it = enc.getEncryptedDataObjects();
// find secret key
@@ -264,7 +237,7 @@ public class PgpDecryptVerify {
if (pbe == null) {
throw new PgpGeneralException(
- context.getString(R.string.error_no_symmetric_encryption_packet));
+ mContext.getString(R.string.error_no_symmetric_encryption_packet));
}
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
@@ -273,7 +246,7 @@ public class PgpDecryptVerify {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- passphrase.toCharArray());
+ mPassphrase.toCharArray());
clear = pbe.getDataStream(decryptorFactory);
@@ -290,33 +263,37 @@ public class PgpDecryptVerify {
Object obj = it.next();
if (obj instanceof PGPPublicKeyEncryptedData) {
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
- secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID());
+ secretKey = ProviderHelper.getPGPSecretKeyByKeyId(mContext, encData.getKeyID());
if (secretKey != null) {
// secret key exists in database
// allow only a specific key for decryption?
- if (enforcedKeyId != 0) {
+ if (mEnforcedKeyId != 0) {
// TODO: improve this code! get master key directly!
- PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, encData.getKeyID());
+ PGPSecretKeyRing secretKeyRing =
+ ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, encData.getKeyID());
long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID();
Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
- Log.d(Constants.TAG, "enforcedKeyId: " + enforcedKeyId);
+ Log.d(Constants.TAG, "enforcedKeyId: " + mEnforcedKeyId);
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
- if (enforcedKeyId != masterKeyId) {
- throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found));
+ if (mEnforcedKeyId != masterKeyId) {
+ throw new PgpGeneralException(
+ mContext.getString(R.string.error_no_secret_key_found));
}
}
pbe = encData;
// if no passphrase was explicitly set try to get it from the cache service
- if (passphrase == null) {
+ if (mPassphrase == null) {
// returns "" if key has no passphrase
- passphrase = PassphraseCacheService.getCachedPassphrase(context, encData.getKeyID());
+ mPassphrase =
+ PassphraseCacheService.getCachedPassphrase(mContext, encData.getKeyID());
- // if passphrase was not cached, return here indicating that a passphrase is missing!
- if (passphrase == null) {
+ // if passphrase was not cached, return here
+ // indicating that a passphrase is missing!
+ if (mPassphrase == null) {
returnData.setKeyPassphraseNeeded(true);
return returnData;
}
@@ -330,7 +307,7 @@ public class PgpDecryptVerify {
}
if (secretKey == null) {
- throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found));
+ throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
}
currentProgress += 5;
@@ -339,14 +316,14 @@ public class PgpDecryptVerify {
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- passphrase.toCharArray());
+ mPassphrase.toCharArray());
privateKey = secretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) {
- throw new PGPException(context.getString(R.string.error_wrong_passphrase));
+ throw new PGPException(mContext.getString(R.string.error_wrong_passphrase));
}
if (privateKey == null) {
throw new PgpGeneralException(
- context.getString(R.string.error_could_not_extract_private_key));
+ mContext.getString(R.string.error_could_not_extract_private_key));
}
currentProgress += 5;
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
@@ -386,7 +363,7 @@ public class PgpDecryptVerify {
for (int i = 0; i < sigList.size(); ++i) {
signature = sigList.get(i);
signatureKey = ProviderHelper
- .getPGPPublicKeyByKeyId(context, signature.getKeyID());
+ .getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
if (signatureKeyId == 0) {
signatureKeyId = signature.getKeyID();
}
@@ -397,7 +374,7 @@ public class PgpDecryptVerify {
signatureKeyId = signature.getKeyID();
String userId = null;
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(
- context, signatureKeyId);
+ mContext, signatureKeyId);
if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
}
@@ -409,7 +386,8 @@ public class PgpDecryptVerify {
signatureResult.setKeyId(signatureKeyId);
if (signature != null) {
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
signature.init(contentVerifierBuilderProvider, signatureKey);
@@ -444,9 +422,9 @@ public class PgpDecryptVerify {
int n;
// TODO: progress calculation is broken here! Try to rework it based on commented code!
// int progress = 0;
- long startPos = data.getStreamPosition();
+ long startPos = mData.getStreamPosition();
while ((n = dataIn.read(buffer)) > 0) {
- outStream.write(buffer, 0, n);
+ mOutStream.write(buffer, 0, n);
// progress += n;
if (signature != null) {
try {
@@ -460,11 +438,11 @@ public class PgpDecryptVerify {
// unknown size, but try to at least have a moving, slowing down progress bar
// currentProgress = startProgress + (endProgress - startProgress) * progress
// / (progress + 100000);
- if (data.getSize() - startPos == 0) {
+ if (mData.getSize() - startPos == 0) {
currentProgress = endProgress;
} else {
currentProgress = (int) (startProgress + (endProgress - startProgress)
- * (data.getStreamPosition() - startPos) / (data.getSize() - startPos));
+ * (mData.getStreamPosition() - startPos) / (mData.getSize() - startPos));
}
updateProgress(currentProgress, 100);
}
@@ -480,7 +458,7 @@ public class PgpDecryptVerify {
signatureResult.setSignatureOnly(false);
//Now check binding signatures
- boolean validKeyBinding = verifyKeyBinding(context, messageSignature, signatureKey);
+ boolean validKeyBinding = verifyKeyBinding(mContext, messageSignature, signatureKey);
boolean validSignature = signature.verify(messageSignature);
// TODO: implement CERTIFIED!
@@ -499,7 +477,7 @@ public class PgpDecryptVerify {
} else {
// failed
Log.d(Constants.TAG, "Integrity verification: failed!");
- throw new PgpGeneralException(context.getString(R.string.error_integrity_check_failed));
+ throw new PgpGeneralException(mContext.getString(R.string.error_integrity_check_failed));
}
} else {
// no integrity check
@@ -555,21 +533,21 @@ public class PgpDecryptVerify {
out.close();
byte[] clearText = out.toByteArray();
- outStream.write(clearText);
+ mOutStream.write(clearText);
updateProgress(R.string.progress_processing_signature, 60, 100);
PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
if (sigList == null) {
- throw new PgpGeneralException(context.getString(R.string.error_corrupt_data));
+ throw new PgpGeneralException(mContext.getString(R.string.error_corrupt_data));
}
PGPSignature signature = null;
long signatureKeyId = 0;
PGPPublicKey signatureKey = null;
for (int i = 0; i < sigList.size(); ++i) {
signature = sigList.get(i);
- signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(context, signature.getKeyID());
+ signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
if (signatureKeyId == 0) {
signatureKeyId = signature.getKeyID();
}
@@ -579,7 +557,7 @@ public class PgpDecryptVerify {
} else {
signatureKeyId = signature.getKeyID();
String userId = null;
- PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
+ PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(mContext,
signatureKeyId);
if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
@@ -623,7 +601,7 @@ public class PgpDecryptVerify {
}
//Now check binding signatures
- boolean validKeyBinding = verifyKeyBinding(context, signature, signatureKey);
+ boolean validKeyBinding = verifyKeyBinding(mContext, signature, signatureKey);
boolean validSignature = signature.verify();
if (validSignature & validKeyBinding) {
@@ -638,7 +616,8 @@ public class PgpDecryptVerify {
return returnData;
}
- private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) {
+ private static boolean verifyKeyBinding(Context context,
+ PGPSignature signature, PGPPublicKey signatureKey) {
long signatureKeyId = signature.getKeyID();
boolean validKeyBinding = false;
@@ -673,7 +652,8 @@ public class PgpDecryptVerify {
//about keys without subkey signing. Can't get it to import a slightly broken one
//either, so we will err on bad subkey binding here.
PGPSignature sig = itr.next();
- if (sig.getKeyID() == masterPublicKey.getKeyID() && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
+ if (sig.getKeyID() == masterPublicKey.getKeyID() &&
+ sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
//check and if ok, check primary key binding.
try {
sig.init(contentVerifierBuilderProvider, masterPublicKey);
@@ -684,34 +664,37 @@ public class PgpDecryptVerify {
continue;
}
- if (validTempSubkeyBinding)
+ if (validTempSubkeyBinding) {
validSubkeyBinding = true;
+ }
if (validTempSubkeyBinding) {
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
masterPublicKey, signingPublicKey);
- if (validPrimaryKeyBinding)
+ if (validPrimaryKeyBinding) {
break;
+ }
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
masterPublicKey, signingPublicKey);
- if (validPrimaryKeyBinding)
+ if (validPrimaryKeyBinding) {
break;
+ }
}
}
}
return (validSubkeyBinding & validPrimaryKeyBinding);
}
- private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector Pkts,
- PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
+ private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts,
+ PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
boolean validPrimaryKeyBinding = false;
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
new JcaPGPContentVerifierBuilderProvider()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureList eSigList;
- if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
+ if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
try {
- eSigList = Pkts.getEmbeddedSignatures();
+ eSigList = pkts.getEmbeddedSignatures();
} catch (IOException e) {
return false;
} catch (PGPException e) {
@@ -723,8 +706,9 @@ public class PgpDecryptVerify {
try {
emSig.init(contentVerifierBuilderProvider, signingPublicKey);
validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
- if (validPrimaryKeyBinding)
+ if (validPrimaryKeyBinding) {
break;
+ }
} catch (PGPException e) {
continue;
} catch (SignatureException e) {
@@ -743,10 +727,9 @@ public class PgpDecryptVerify {
* @param sig
* @param line
* @throws SignatureException
- * @throws IOException
*/
private static void processLine(PGPSignature sig, byte[] line)
- throws SignatureException, IOException {
+ throws SignatureException {
int length = getLengthWithoutWhiteSpace(line);
if (length > 0) {
sig.update(line, 0, length);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java
index 0477c4fdf..d4a4f6075 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java
@@ -19,36 +19,35 @@ package org.sufficientlysecure.keychain.pgp;
import android.os.Parcel;
import android.os.Parcelable;
-
import org.openintents.openpgp.OpenPgpSignatureResult;
public class PgpDecryptVerifyResult implements Parcelable {
- boolean symmetricPassphraseNeeded;
- boolean keyPassphraseNeeded;
- OpenPgpSignatureResult signatureResult;
+ boolean mSymmetricPassphraseNeeded;
+ boolean mKeyPassphraseNeeded;
+ OpenPgpSignatureResult mSignatureResult;
public boolean isSymmetricPassphraseNeeded() {
- return symmetricPassphraseNeeded;
+ return mSymmetricPassphraseNeeded;
}
public void setSymmetricPassphraseNeeded(boolean symmetricPassphraseNeeded) {
- this.symmetricPassphraseNeeded = symmetricPassphraseNeeded;
+ this.mSymmetricPassphraseNeeded = symmetricPassphraseNeeded;
}
public boolean isKeyPassphraseNeeded() {
- return keyPassphraseNeeded;
+ return mKeyPassphraseNeeded;
}
public void setKeyPassphraseNeeded(boolean keyPassphraseNeeded) {
- this.keyPassphraseNeeded = keyPassphraseNeeded;
+ this.mKeyPassphraseNeeded = keyPassphraseNeeded;
}
public OpenPgpSignatureResult getSignatureResult() {
- return signatureResult;
+ return mSignatureResult;
}
public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
- this.signatureResult = signatureResult;
+ this.mSignatureResult = signatureResult;
}
public PgpDecryptVerifyResult() {
@@ -56,9 +55,9 @@ public class PgpDecryptVerifyResult implements Parcelable {
}
public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) {
- this.symmetricPassphraseNeeded = b.symmetricPassphraseNeeded;
- this.keyPassphraseNeeded = b.keyPassphraseNeeded;
- this.signatureResult = b.signatureResult;
+ this.mSymmetricPassphraseNeeded = b.mSymmetricPassphraseNeeded;
+ this.mKeyPassphraseNeeded = b.mKeyPassphraseNeeded;
+ this.mSignatureResult = b.mSignatureResult;
}
@@ -67,17 +66,17 @@ public class PgpDecryptVerifyResult implements Parcelable {
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeByte((byte) (symmetricPassphraseNeeded ? 1 : 0));
- dest.writeByte((byte) (keyPassphraseNeeded ? 1 : 0));
- dest.writeParcelable(signatureResult, 0);
+ dest.writeByte((byte) (mSymmetricPassphraseNeeded ? 1 : 0));
+ dest.writeByte((byte) (mKeyPassphraseNeeded ? 1 : 0));
+ dest.writeParcelable(mSignatureResult, 0);
}
public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() {
public PgpDecryptVerifyResult createFromParcel(final Parcel source) {
PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult();
- vr.symmetricPassphraseNeeded = source.readByte() == 1;
- vr.keyPassphraseNeeded = source.readByte() == 1;
- vr.signatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
+ vr.mSymmetricPassphraseNeeded = source.readByte() == 1;
+ vr.mKeyPassphraseNeeded = source.readByte() == 1;
+ vr.mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
return vr;
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
index 7ac904d89..2680d77af 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
@@ -17,22 +17,10 @@
package org.sufficientlysecure.keychain.pgp;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.security.SecureRandom;
-import java.util.Iterator;
-import java.util.regex.Pattern;
-
-import org.spongycastle.openpgp.PGPEncryptedDataList;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPUtil;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import org.spongycastle.openpgp.*;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
@@ -42,21 +30,25 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.security.SecureRandom;
+import java.util.Iterator;
+import java.util.regex.Pattern;
public class PgpHelper {
- public static Pattern PGP_MESSAGE = Pattern.compile(
+ public static final Pattern PGP_MESSAGE = Pattern.compile(
".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL);
- public static Pattern PGP_SIGNED_MESSAGE = Pattern
+ public static final Pattern PGP_SIGNED_MESSAGE = Pattern
.compile(
".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
Pattern.DOTALL);
- public static Pattern PGP_PUBLIC_KEY = Pattern.compile(
+ public static final Pattern PGP_PUBLIC_KEY = Pattern.compile(
".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
Pattern.DOTALL);
@@ -140,7 +132,7 @@ public class PgpHelper {
/**
* Generate a random filename
- *
+ *
* @param length
* @return
*/
@@ -170,7 +162,7 @@ public class PgpHelper {
/**
* Go once through stream to get length of stream. The length is later used to display progress
* when encrypting/decrypting
- *
+ *
* @param in
* @return
* @throws IOException
@@ -187,17 +179,16 @@ public class PgpHelper {
/**
* Deletes file securely by overwriting it with random data before deleting it.
- *
+ * <p/>
* TODO: Does this really help on flash storage?
- *
+ *
* @param context
* @param progress
* @param file
- * @throws FileNotFoundException
* @throws IOException
*/
public static void deleteFileSecurely(Context context, ProgressDialogUpdater progress, File file)
- throws FileNotFoundException, IOException {
+ throws IOException {
long length = file.length();
SecureRandom random = new SecureRandom();
RandomAccessFile raf = new RandomAccessFile(file, "rws");
@@ -207,8 +198,9 @@ public class PgpHelper {
int pos = 0;
String msg = context.getString(R.string.progress_deleting_securely, file.getName());
while (pos < length) {
- if (progress != null)
+ if (progress != null) {
progress.setProgress(msg, (int) (100 * pos / length), 100);
+ }
random.nextBytes(data);
raf.write(data);
pos += data.length;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index 2495a212c..0e0fdec83 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -17,24 +17,11 @@
package org.sufficientlysecure.keychain.pgp;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Environment;
import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPKeyRing;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.*;
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
@@ -43,28 +30,37 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.util.HkpKeyServer;
-import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.util.IterableIterator;
+import org.sufficientlysecure.keychain.util.*;
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Environment;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.Provider;
+import java.util.ArrayList;
+import java.util.List;
public class PgpImportExport {
+
private Context mContext;
private ProgressDialogUpdater mProgress;
+ private KeychainServiceListener mKeychainServiceListener;
+
public PgpImportExport(Context context, ProgressDialogUpdater progress) {
super();
this.mContext = context;
this.mProgress = progress;
}
+ public PgpImportExport(Context context,
+ ProgressDialogUpdater progress, KeychainServiceListener keychainListener) {
+ super();
+ this.mContext = context;
+ this.mProgress = progress;
+ this.mKeychainServiceListener = keychainListener;
+ }
+
public void updateProgress(int message, int current, int total) {
if (mProgress != null) {
mProgress.setProgress(message, current, total);
@@ -85,8 +81,9 @@ public class PgpImportExport {
public boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ArmoredOutputStream aos = new ArmoredOutputStream(bos);
+ ArmoredOutputStream aos = null;
try {
+ aos = new ArmoredOutputStream(bos);
aos.write(keyring.getEncoded());
aos.close();
@@ -101,7 +98,8 @@ public class PgpImportExport {
return false;
} finally {
try {
- bos.close();
+ if (aos != null) { aos.close(); }
+ if (bos != null) { bos.close(); }
} catch (IOException e) {
}
}
@@ -161,59 +159,68 @@ public class PgpImportExport {
return returnData;
}
- public Bundle exportKeyRings(ArrayList<Long> keyRingMasterKeyIds, int keyType,
- OutputStream outStream) throws PgpGeneralException, FileNotFoundException,
+ public Bundle exportKeyRings(ArrayList<Long> publicKeyRingMasterIds, ArrayList<Long> secretKeyRingMasterIds,
+ OutputStream outStream) throws PgpGeneralException,
PGPException, IOException {
Bundle returnData = new Bundle();
+ int masterKeyIdsSize = publicKeyRingMasterIds.size() + secretKeyRingMasterIds.size();
+ int progress = 0;
+
updateProgress(
mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
- keyRingMasterKeyIds.size()), 0, 100);
+ masterKeyIdsSize), 0, 100);
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new PgpGeneralException(
mContext.getString(R.string.error_external_storage_not_ready));
}
+ // For each public masterKey id
+ for (long pubKeyMasterId : publicKeyRingMasterIds) {
+ progress++;
+ // Create an output stream
+ ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
+ arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext));
+
+ updateProgress(progress * 100 / masterKeyIdsSize, 100);
+ PGPPublicKeyRing publicKeyRing =
+ ProviderHelper.getPGPPublicKeyRingByMasterKeyId(mContext, pubKeyMasterId);
+
+ if (publicKeyRing != null) {
+ publicKeyRing.encode(arOutStream);
+ }
- if (keyType == Id.type.secret_key) {
- ArmoredOutputStream outSec = new ArmoredOutputStream(outStream);
- outSec.setHeader("Version", PgpHelper.getFullVersion(mContext));
-
- for (int i = 0; i < keyRingMasterKeyIds.size(); ++i) {
- updateProgress(i * 100 / keyRingMasterKeyIds.size() / 2, 100);
+ if (mKeychainServiceListener.hasServiceStopped()) {
+ arOutStream.close();
+ return null;
+ }
- PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(
- mContext, keyRingMasterKeyIds.get(i));
+ arOutStream.close();
+ }
- if (secretKeyRing != null) {
- secretKeyRing.encode(outSec);
- }
- }
- outSec.close();
- } else {
- // export public keyrings...
- ArmoredOutputStream outPub = new ArmoredOutputStream(outStream);
- outPub.setHeader("Version", PgpHelper.getFullVersion(mContext));
-
- for (int i = 0; i < keyRingMasterKeyIds.size(); ++i) {
- // double the needed time if exporting both public and secret parts
- if (keyType == Id.type.secret_key) {
- updateProgress(i * 100 / keyRingMasterKeyIds.size() / 2, 100);
- } else {
- updateProgress(i * 100 / keyRingMasterKeyIds.size(), 100);
- }
+ // For each secret masterKey id
+ for (long secretKeyMasterId : secretKeyRingMasterIds) {
+ progress++;
+ // Create an output stream
+ ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
+ arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext));
- PGPPublicKeyRing publicKeyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId(
- mContext, keyRingMasterKeyIds.get(i));
+ updateProgress(progress * 100 / masterKeyIdsSize, 100);
+ PGPSecretKeyRing secretKeyRing =
+ ProviderHelper.getPGPSecretKeyRingByMasterKeyId(mContext, secretKeyMasterId);
- if (publicKeyRing != null) {
- publicKeyRing.encode(outPub);
- }
+ if (secretKeyRing != null) {
+ secretKeyRing.encode(arOutStream);
+ }
+ if (mKeychainServiceListener.hasServiceStopped()) {
+ arOutStream.close();
+ return null;
}
- outPub.close();
+
+ arOutStream.close();
}
- returnData.putInt(KeychainIntentService.RESULT_EXPORT, keyRingMasterKeyIds.size());
+ returnData.putInt(KeychainIntentService.RESULT_EXPORT, masterKeyIdsSize);
updateProgress(R.string.progress_done, 100, 100);
@@ -234,7 +241,7 @@ public class PgpImportExport {
for (PGPSecretKey testSecretKey : new IterableIterator<PGPSecretKey>(
secretKeyRing.getSecretKeys())) {
if (!testSecretKey.isMasterKey()) {
- if (PgpKeyHelper.isSecretKeyPrivateEmpty(testSecretKey)) {
+ if (testSecretKey.isPrivateKeyEmpty()) {
// this is bad, something is very wrong...
save = false;
status = Id.return_value.bad;
@@ -255,8 +262,9 @@ public class PgpImportExport {
}
newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key);
}
- if (newPubRing != null)
+ if (newPubRing != null) {
ProviderHelper.saveKeyRing(mContext, newPubRing);
+ }
// TODO: remove status returns, use exceptions!
status = Id.return_value.ok;
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
index c1c6f3088..b4bf0747f 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
@@ -17,28 +17,27 @@
package org.sufficientlysecure.keychain.pgp;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.Vector;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import android.content.Context;
+import android.graphics.Color;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
import org.spongycastle.bcpg.sig.KeyFlags;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.*;
+import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.Context;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class PgpKeyHelper {
@@ -466,55 +465,30 @@ public class PgpKeyHelper {
String algorithmStr;
switch (algorithm) {
- case PGPPublicKey.RSA_ENCRYPT:
- case PGPPublicKey.RSA_GENERAL:
- case PGPPublicKey.RSA_SIGN: {
- algorithmStr = "RSA";
- break;
- }
-
- case PGPPublicKey.DSA: {
- algorithmStr = "DSA";
- break;
- }
-
- case PGPPublicKey.ELGAMAL_ENCRYPT:
- case PGPPublicKey.ELGAMAL_GENERAL: {
- algorithmStr = "ElGamal";
- break;
- }
+ case PGPPublicKey.RSA_ENCRYPT:
+ case PGPPublicKey.RSA_GENERAL:
+ case PGPPublicKey.RSA_SIGN: {
+ algorithmStr = "RSA";
+ break;
+ }
- default: {
- algorithmStr = "Unknown";
- break;
- }
- }
- return algorithmStr + ", " + keySize + " bit";
- }
+ case PGPPublicKey.DSA: {
+ algorithmStr = "DSA";
+ break;
+ }
- /**
- * Converts fingerprint to hex with whitespaces after 4 characters
- *
- * @param fp
- * @return
- */
- public static String convertFingerprintToHex(byte[] fp, boolean chunked) {
- String fingerPrint = "";
- for (int i = 0; i < fp.length; ++i) {
- if (chunked && i != 0 && i % 10 == 0) {
- fingerPrint += " ";
- } else if (chunked && i != 0 && i % 2 == 0) {
- fingerPrint += " ";
+ case PGPPublicKey.ELGAMAL_ENCRYPT:
+ case PGPPublicKey.ELGAMAL_GENERAL: {
+ algorithmStr = "ElGamal";
+ break;
}
- String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase(Locale.US);
- while (chunk.length() < 2) {
- chunk = "0" + chunk;
+
+ default: {
+ algorithmStr = "Unknown";
+ break;
}
- fingerPrint += chunk;
}
-
- return fingerPrint;
-
+ return algorithmStr + ", " + keySize + " bit";
}
public static String getFingerPrint(Context context, long keyId) {
@@ -529,55 +503,150 @@ public class PgpKeyHelper {
key = secretKey.getPublicKey();
}
- return convertFingerprintToHex(key.getFingerprint(), true);
- }
-
- public static boolean isSecretKeyPrivateEmpty(PGPSecretKey secretKey) {
- return secretKey.isPrivateKeyEmpty();
+ return convertFingerprintToHex(key.getFingerprint());
}
-// public static boolean isSecretKeyPrivateEmpty(Context context, long keyId) {
-// PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId);
-// if (secretKey == null) {
-// Log.e(Constants.TAG, "Key could not be found!");
-// return false; // could be a public key, assume it is not empty
-// }
-// return isSecretKeyPrivateEmpty(secretKey);
-// }
+ /**
+ * Converts fingerprint to hex (optional: with whitespaces after 4 characters)
+ * <p/>
+ * Fingerprint is shown using lowercase characters. Studies have shown that humans can
+ * better differentiate between numbers and letters when letters are lowercase.
+ *
+ * @param fingerprint
+ * @param split split into 4 character chunks
+ * @return
+ */
+ public static String convertFingerprintToHex(byte[] fingerprint) {
+ String hexString = Hex.toHexString(fingerprint);
- public static String convertKeyIdToHex(long keyId) {
- String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US);
- while (fingerPrint.length() < 8) {
- fingerPrint = "0" + fingerPrint;
- }
- return fingerPrint;
+ return hexString;
}
/**
- * TODO: documentation
- *
+ * Convert key id from long to 64 bit hex string
+ * <p/>
+ * V4: "The Key ID is the low-order 64 bits of the fingerprint"
+ * <p/>
+ * see http://tools.ietf.org/html/rfc4880#section-12.2
+ *
* @param keyId
* @return
*/
- public static String convertKeyToHex(long keyId) {
- return convertKeyIdToHex(keyId >> 32) + convertKeyIdToHex(keyId);
+ public static String convertKeyIdToHex(long keyId) {
+ long upper = keyId >> 32;
+ if (upper == 0) {
+ // this is a short key id
+ return convertKeyIdToHexShort(keyId);
+ }
+ return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId);
}
- public static long convertHexToKeyId(String data) {
- int len = data.length();
- String s2 = data.substring(len - 8);
- String s1 = data.substring(0, len - 8);
- return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16);
+ public static String convertKeyIdToHexShort(long keyId) {
+ return "0x" + convertKeyIdToHex32bit(keyId);
+ }
+
+ private static String convertKeyIdToHex32bit(long keyId) {
+ String hexString = Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.US);
+ while (hexString.length() < 8) {
+ hexString = "0" + hexString;
+ }
+ return hexString;
+ }
+
+
+ public static SpannableStringBuilder colorizeFingerprint(String fingerprint) {
+ // split by 4 characters
+ fingerprint = fingerprint.replaceAll("(.{4})(?!$)", "$1 ");
+
+ // add line breaks to have a consistent "image" that can be recognized
+ char[] chars = fingerprint.toCharArray();
+ chars[24] = '\n';
+ fingerprint = String.valueOf(chars);
+
+ SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint);
+ try {
+ // for each 4 characters of the fingerprint + 1 space
+ for (int i = 0; i < fingerprint.length(); i += 5) {
+ int spanEnd = Math.min(i + 4, fingerprint.length());
+ String fourChars = fingerprint.substring(i, spanEnd);
+
+ int raw = Integer.parseInt(fourChars, 16);
+ byte[] bytes = {(byte) ((raw >> 8) & 0xff - 128), (byte) (raw & 0xff - 128)};
+ int[] color = getRgbForData(bytes);
+ int r = color[0];
+ int g = color[1];
+ int b = color[2];
+
+ // we cannot change black by multiplication, so adjust it to an almost-black grey,
+ // which will then be brightened to the minimal brightness level
+ if (r == 0 && g == 0 && b == 0) {
+ r = 1;
+ g = 1;
+ b = 1;
+ }
+
+ // Convert rgb to brightness
+ double brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b;
+
+ // If a color is too dark to be seen on black,
+ // then brighten it up to a minimal brightness.
+ if (brightness < 80) {
+ double factor = 80.0 / brightness;
+ r = Math.min(255, (int) (r * factor));
+ g = Math.min(255, (int) (g * factor));
+ b = Math.min(255, (int) (b * factor));
+
+ // If it is too light, then darken it to a respective maximal brightness.
+ } else if (brightness > 180) {
+ double factor = 180.0 / brightness;
+ r = (int) (r * factor);
+ g = (int) (g * factor);
+ b = (int) (b * factor);
+ }
+
+ // Create a foreground color with the 3 digest integers as RGB
+ // and then converting that int to hex to use as a color
+ sb.setSpan(new ForegroundColorSpan(Color.rgb(r, g, b)),
+ i, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+ } catch (Exception e) {
+ Log.e(Constants.TAG, "Colorization failed", e);
+ // if anything goes wrong, then just display the fingerprint without colour,
+ // instead of partially correct colour or wrong colours
+ return new SpannableStringBuilder(fingerprint);
+ }
+
+ return sb;
+ }
+
+ /**
+ * Converts the given bytes to a unique RGB color using SHA1 algorithm
+ *
+ * @param bytes
+ * @return an integer array containing 3 numeric color representations (Red, Green, Black)
+ * @throws java.security.NoSuchAlgorithmException
+ * @throws java.security.DigestException
+ */
+ private static int[] getRgbForData(byte[] bytes) throws NoSuchAlgorithmException, DigestException {
+ MessageDigest md = MessageDigest.getInstance("SHA1");
+
+ md.update(bytes);
+ byte[] digest = md.digest();
+
+ int[] result = {((int) digest[0] + 256) % 256,
+ ((int) digest[1] + 256) % 256,
+ ((int) digest[2] + 256) % 256};
+ return result;
}
/**
* Splits userId string into naming part, email part, and comment part
- *
+ *
* @param userId
* @return array with naming (0), email (1), comment (2)
*/
public static String[] splitUserId(String userId) {
- String[] result = new String[] { null, null, null };
+ String[] result = new String[]{null, null, null};
if (userId == null || userId.equals("")) {
return result;
@@ -598,7 +667,6 @@ public class PgpKeyHelper {
result[0] = matcher.group(1);
result[1] = matcher.group(3);
result[2] = matcher.group(2);
- return result;
}
return result;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index b7f84ccdc..05ca99578 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -30,35 +30,19 @@ import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.TimeZone;
-
+import android.content.Context;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
-import org.spongycastle.openpgp.PGPEncryptedData;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPKeyPair;
-import org.spongycastle.openpgp.PGPKeyRingGenerator;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.openpgp.PGPSignatureGenerator;
-import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.*;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.*;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
@@ -70,20 +54,34 @@ import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import android.content.Context;
import android.util.Pair;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Primes;
+import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TimeZone;
public class PgpKeyOperation {
private final Context mContext;
private final ProgressDialogUpdater mProgress;
- private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[] {
+ private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5,
- SymmetricKeyAlgorithmTags.TRIPLE_DES };
- private static final int[] PREFERRED_HASH_ALGORITHMS = new int[] { HashAlgorithmTags.SHA1,
- HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160 };
- private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[] {
+ SymmetricKeyAlgorithmTags.TRIPLE_DES};
+ private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{HashAlgorithmTags.SHA1,
+ HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160};
+ private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{
CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2,
- CompressionAlgorithmTags.ZIP };
+ CompressionAlgorithmTags.ZIP};
public PgpKeyOperation(Context context, ProgressDialogUpdater progress) {
super();
@@ -104,8 +102,9 @@ public class PgpKeyOperation {
}
public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase,
- boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
- PgpGeneralException, InvalidAlgorithmParameterException {
+ boolean isMasterKey)
+ throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
+ PgpGeneralException, InvalidAlgorithmParameterException {
if (keySize < 512) {
throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit));
@@ -119,41 +118,41 @@ public class PgpKeyOperation {
KeyPairGenerator keyGen;
switch (algorithmChoice) {
- case Id.choice.algorithm.dsa: {
- keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- keyGen.initialize(keySize, new SecureRandom());
- algorithm = PGPPublicKey.DSA;
- break;
- }
-
- case Id.choice.algorithm.elgamal: {
- if (isMasterKey) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_master_key_must_not_be_el_gamal));
+ case Id.choice.algorithm.dsa: {
+ keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ keyGen.initialize(keySize, new SecureRandom());
+ algorithm = PGPPublicKey.DSA;
+ break;
}
- keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- BigInteger p = Primes.getBestPrime(keySize);
- BigInteger g = new BigInteger("2");
- ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
+ case Id.choice.algorithm.elgamal: {
+ if (isMasterKey) {
+ throw new PgpGeneralException(
+ mContext.getString(R.string.error_master_key_must_not_be_el_gamal));
+ }
+ keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ BigInteger p = Primes.getBestPrime(keySize);
+ BigInteger g = new BigInteger("2");
- keyGen.initialize(elParams);
- algorithm = PGPPublicKey.ELGAMAL_ENCRYPT;
- break;
- }
+ ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
- case Id.choice.algorithm.rsa: {
- keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- keyGen.initialize(keySize, new SecureRandom());
+ keyGen.initialize(elParams);
+ algorithm = PGPPublicKey.ELGAMAL_ENCRYPT;
+ break;
+ }
- algorithm = PGPPublicKey.RSA_GENERAL;
- break;
- }
+ case Id.choice.algorithm.rsa: {
+ keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ keyGen.initialize(keySize, new SecureRandom());
- default: {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_unknown_algorithm_choice));
- }
+ algorithm = PGPPublicKey.RSA_GENERAL;
+ break;
+ }
+
+ default: {
+ throw new PgpGeneralException(
+ mContext.getString(R.string.error_unknown_algorithm_choice));
+ }
}
// build new key pair
@@ -170,11 +169,10 @@ public class PgpKeyOperation {
return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
sha1Calc, isMasterKey, keyEncryptor);
-
}
public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase,
- String newPassPhrase) throws IOException, PGPException {
+ String newPassPhrase) throws IOException, PGPException {
updateProgress(R.string.progress_building_key, 0, 100);
if (oldPassPhrase == null) {
@@ -221,15 +219,15 @@ public class PgpKeyOperation {
updateProgress(R.string.progress_certifying_master_key, 20, 100);
int user_id_index = 0;
for (String userId : userIds) {
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
+ PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
+ masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
- sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
+ sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
- PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
- masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification);
+ PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
+ masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification);
user_id_index++;
}
@@ -280,7 +278,7 @@ public class PgpKeyOperation {
updateProgress(R.string.progress_adding_sub_keys, 40, 100);
for (int i = 1; i < keys.size(); ++i) {
- updateProgress(40 + 50 * (i - 1) / (keys.size() - 1), 100);
+ updateProgress(40 + 40 * (i - 1) / (keys.size() - 1), 100);
PGPSecretKey subKey = keys.get(i);
PGPPublicKey subPublicKey = subKey.getPublicKey();
@@ -345,7 +343,7 @@ public class PgpKeyOperation {
updateProgress(R.string.progress_done, 100, 100);
}
- public void buildSecretKey(SaveKeyringParcel saveParcel) throws PgpGeneralException,
+ public void buildSecretKey (SaveKeyringParcel saveParcel)throws PgpGeneralException,
PGPException, SignatureException, IOException {
updateProgress(R.string.progress_building_key, 0, 100);
@@ -387,7 +385,7 @@ public class PgpKeyOperation {
Todo
identify more things which need to be preserved - e.g. trust levels?
user attributes
- */
+ */
if (saveParcel.deletedKeys != null) {
for (PGPSecretKey dKey : saveParcel.deletedKeys) {
@@ -546,7 +544,7 @@ public class PgpKeyOperation {
unhashedPacketsGen.generate(), certificationSignerBuilder, keyEncryptor);
for (int i = 1; i < saveParcel.keys.size(); ++i) {
- updateProgress(40 + 50 * i/ saveParcel.keys.size(), 100);
+ updateProgress(40 + 50 * i / saveParcel.keys.size(), 100);
if (saveParcel.moddedKeys[i]) {
PGPSecretKey subKey = saveParcel.keys.get(i);
PGPPublicKey subPublicKey = subKey.getPublicKey();
@@ -558,8 +556,8 @@ public class PgpKeyOperation {
"".toCharArray());
} else {
keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- saveParcel.oldPassPhrase.toCharArray());
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ saveParcel.oldPassPhrase.toCharArray());
}
PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2);
PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey, subPrivateKey);
@@ -642,50 +640,80 @@ public class PgpKeyOperation {
mKR = PGPSecretKeyRing.copyWithNewPassword(mKR, keyDecryptor, keyEncryptorNew);
updateProgress(R.string.progress_saving_key_ring, 90, 100);
+ /* additional handy debug info
+
+ Log.d(Constants.TAG, " ------- in private key -------");
+
+ for(String uid : new IterableIterator<String>(secretKeyRing.getPublicKey().getUserIDs())) {
+ for(PGPSignature sig : new IterableIterator<PGPSignature>(secretKeyRing.getPublicKey().getSignaturesForID(uid))) {
+ Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
+ }
+
+ }
+
+ Log.d(Constants.TAG, " ------- in public key -------");
+
+ for(String uid : new IterableIterator<String>(publicKeyRing.getPublicKey().getUserIDs())) {
+ for(PGPSignature sig : new IterableIterator<PGPSignature>(publicKeyRing.getPublicKey().getSignaturesForID(uid))) {
+ Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
+ }
+ }
+
+ */
+
+
ProviderHelper.saveKeyRing(mContext, mKR);
ProviderHelper.saveKeyRing(mContext, pKR);
updateProgress(R.string.progress_done, 100, 100);
}
- public PGPPublicKeyRing certifyKey(long masterKeyId, long pubKeyId, String passphrase)
- throws PgpGeneralException, PGPException, SignatureException {
+ public PGPPublicKeyRing certifyKey(long masterKeyId, long pubKeyId, List<String> userIds, String passphrase)
+ throws PgpGeneralException, NoSuchAlgorithmException, NoSuchProviderException,
+ PGPException, SignatureException {
if (passphrase == null) {
throw new PgpGeneralException("Unable to obtain passphrase");
} else {
- PGPPublicKeyRing pubring = ProviderHelper
- .getPGPPublicKeyRingByKeyId(mContext, pubKeyId);
- PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(mContext, masterKeyId);
- if (certificationKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
+ // create a signatureGenerator from the supplied masterKeyId and passphrase
+ PGPSignatureGenerator signatureGenerator; {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
-
- // TODO: SHA256 fixed?
- JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
- certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(mContext, masterKeyId);
+ if (certificationKey == null) {
+ throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
+ }
- PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
- contentSignerBuilder);
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
+ PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new PgpGeneralException(
+ mContext.getString(R.string.error_could_not_extract_private_key));
+ }
- signatureGenerator.init(PGPSignature.DIRECT_KEY, signaturePrivateKey);
+ // TODO: SHA256 fixed?
+ JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
+ certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, signaturePrivateKey);
+ }
- PGPSignatureSubpacketVector packetVector = spGen.generate();
- signatureGenerator.setHashedSubpackets(packetVector);
+ { // supply signatureGenerator with a SubpacketVector
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ PGPSignatureSubpacketVector packetVector = spGen.generate();
+ signatureGenerator.setHashedSubpackets(packetVector);
+ }
- PGPPublicKey signedKey = PGPPublicKey.addCertification(pubring.getPublicKey(pubKeyId),
- signatureGenerator.generate());
+ // fetch public key ring, add the certification and return it
+ PGPPublicKeyRing pubring = ProviderHelper
+ .getPGPPublicKeyRingByKeyId(mContext, pubKeyId);
+ PGPPublicKey signedKey = pubring.getPublicKey(pubKeyId);
+ for(String userId : new IterableIterator<String>(userIds.iterator())) {
+ PGPSignature sig = signatureGenerator.generateCertification(userId, signedKey);
+ signedKey = PGPPublicKey.addCertification(signedKey, userId, sig);
+ }
pubring = PGPPublicKeyRing.insertPublicKey(pubring, signedKey);
return pubring;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
index ba1182c1b..737e9c75d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -18,28 +18,11 @@
package org.sufficientlysecure.keychain.pgp;
import android.content.Context;
-
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream;
-import org.spongycastle.openpgp.PGPCompressedDataGenerator;
-import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPLiteralData;
-import org.spongycastle.openpgp.PGPLiteralDataGenerator;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.openpgp.PGPSignatureGenerator;
-import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.spongycastle.openpgp.PGPV3SignatureGenerator;
+import org.spongycastle.openpgp.*;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
+import org.spongycastle.openpgp.operator.jcajce.*;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
@@ -49,11 +32,7 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
+import java.io.*;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
@@ -63,110 +42,110 @@ import java.util.Date;
* This class uses a Builder pattern!
*/
public class PgpSignEncrypt {
- private Context context;
- private InputData data;
- private OutputStream outStream;
-
- private ProgressDialogUpdater progress;
- private boolean enableAsciiArmorOutput;
- private int compressionId;
- private long[] encryptionKeyIds;
- private String encryptionPassphrase;
- private int symmetricEncryptionAlgorithm;
- private long signatureKeyId;
- private int signatureHashAlgorithm;
- private boolean signatureForceV3;
- private String signaturePassphrase;
+ private Context mContext;
+ private InputData mData;
+ private OutputStream mOutStream;
+
+ private ProgressDialogUpdater mProgress;
+ private boolean mEnableAsciiArmorOutput;
+ private int mCompressionId;
+ private long[] mEncryptionKeyIds;
+ private String mEncryptionPassphrase;
+ private int mSymmetricEncryptionAlgorithm;
+ private long mSignatureKeyId;
+ private int mSignatureHashAlgorithm;
+ private boolean mSignatureForceV3;
+ private String mSignaturePassphrase;
private PgpSignEncrypt(Builder builder) {
// private Constructor can only be called from Builder
- this.context = builder.context;
- this.data = builder.data;
- this.outStream = builder.outStream;
-
- this.progress = builder.progress;
- this.enableAsciiArmorOutput = builder.enableAsciiArmorOutput;
- this.compressionId = builder.compressionId;
- this.encryptionKeyIds = builder.encryptionKeyIds;
- this.encryptionPassphrase = builder.encryptionPassphrase;
- this.symmetricEncryptionAlgorithm = builder.symmetricEncryptionAlgorithm;
- this.signatureKeyId = builder.signatureKeyId;
- this.signatureHashAlgorithm = builder.signatureHashAlgorithm;
- this.signatureForceV3 = builder.signatureForceV3;
- this.signaturePassphrase = builder.signaturePassphrase;
+ this.mContext = builder.mContext;
+ this.mData = builder.mData;
+ this.mOutStream = builder.mOutStream;
+
+ this.mProgress = builder.mProgress;
+ this.mEnableAsciiArmorOutput = builder.mEnableAsciiArmorOutput;
+ this.mCompressionId = builder.mCompressionId;
+ this.mEncryptionKeyIds = builder.mEncryptionKeyIds;
+ this.mEncryptionPassphrase = builder.mEncryptionPassphrase;
+ this.mSymmetricEncryptionAlgorithm = builder.mSymmetricEncryptionAlgorithm;
+ this.mSignatureKeyId = builder.mSignatureKeyId;
+ this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
+ this.mSignatureForceV3 = builder.mSignatureForceV3;
+ this.mSignaturePassphrase = builder.mSignaturePassphrase;
}
public static class Builder {
// mandatory parameter
- private Context context;
- private InputData data;
- private OutputStream outStream;
+ private Context mContext;
+ private InputData mData;
+ private OutputStream mOutStream;
// optional
- private ProgressDialogUpdater progress = null;
- private boolean enableAsciiArmorOutput = false;
- private int compressionId = Id.choice.compression.none;
- private long[] encryptionKeyIds = new long[0];
- private String encryptionPassphrase = null;
- private int symmetricEncryptionAlgorithm = 0;
- private long signatureKeyId = Id.key.none;
- private int signatureHashAlgorithm = 0;
- private boolean signatureForceV3 = false;
- private String signaturePassphrase = null;
+ private ProgressDialogUpdater mProgress = null;
+ private boolean mEnableAsciiArmorOutput = false;
+ private int mCompressionId = Id.choice.compression.none;
+ private long[] mEncryptionKeyIds = new long[0];
+ private String mEncryptionPassphrase = null;
+ private int mSymmetricEncryptionAlgorithm = 0;
+ private long mSignatureKeyId = Id.key.none;
+ private int mSignatureHashAlgorithm = 0;
+ private boolean mSignatureForceV3 = false;
+ private String mSignaturePassphrase = null;
public Builder(Context context, InputData data, OutputStream outStream) {
- this.context = context;
- this.data = data;
- this.outStream = outStream;
+ this.mContext = context;
+ this.mData = data;
+ this.mOutStream = outStream;
}
public Builder progress(ProgressDialogUpdater progress) {
- this.progress = progress;
+ this.mProgress = progress;
return this;
}
public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
- this.enableAsciiArmorOutput = enableAsciiArmorOutput;
+ this.mEnableAsciiArmorOutput = enableAsciiArmorOutput;
return this;
}
public Builder compressionId(int compressionId) {
- this.compressionId = compressionId;
+ this.mCompressionId = compressionId;
return this;
}
public Builder encryptionKeyIds(long[] encryptionKeyIds) {
- this.encryptionKeyIds = encryptionKeyIds;
+ this.mEncryptionKeyIds = encryptionKeyIds;
return this;
}
public Builder encryptionPassphrase(String encryptionPassphrase) {
- this.encryptionPassphrase = encryptionPassphrase;
+ this.mEncryptionPassphrase = encryptionPassphrase;
return this;
}
public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
- this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
+ this.mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
return this;
}
public Builder signatureKeyId(long signatureKeyId) {
- this.signatureKeyId = signatureKeyId;
+ this.mSignatureKeyId = signatureKeyId;
return this;
}
public Builder signatureHashAlgorithm(int signatureHashAlgorithm) {
- this.signatureHashAlgorithm = signatureHashAlgorithm;
+ this.mSignatureHashAlgorithm = signatureHashAlgorithm;
return this;
}
public Builder signatureForceV3(boolean signatureForceV3) {
- this.signatureForceV3 = signatureForceV3;
+ this.mSignatureForceV3 = signatureForceV3;
return this;
}
public Builder signaturePassphrase(String signaturePassphrase) {
- this.signaturePassphrase = signaturePassphrase;
+ this.mSignaturePassphrase = signaturePassphrase;
return this;
}
@@ -176,14 +155,14 @@ public class PgpSignEncrypt {
}
public void updateProgress(int message, int current, int total) {
- if (progress != null) {
- progress.setProgress(message, current, total);
+ if (mProgress != null) {
+ mProgress.setProgress(message, current, total);
}
}
public void updateProgress(int current, int total) {
- if (progress != null) {
- progress.setProgress(current, total);
+ if (mProgress != null) {
+ mProgress.setProgress(current, total);
}
}
@@ -201,17 +180,17 @@ public class PgpSignEncrypt {
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
- boolean enableSignature = signatureKeyId != Id.key.none;
- boolean enableEncryption = (encryptionKeyIds.length != 0 || encryptionPassphrase != null);
- boolean enableCompression = (enableEncryption && compressionId != Id.choice.compression.none);
+ boolean enableSignature = mSignatureKeyId != Id.key.none;
+ boolean enableEncryption = (mEncryptionKeyIds.length != 0 || mEncryptionPassphrase != null);
+ boolean enableCompression = (enableEncryption && mCompressionId != Id.choice.compression.none);
Log.d(Constants.TAG, "enableSignature:" + enableSignature
+ "\nenableEncryption:" + enableEncryption
+ "\nenableCompression:" + enableCompression
- + "\nenableAsciiArmorOutput:" + enableAsciiArmorOutput);
+ + "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
int signatureType;
- if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
+ if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
// for sign-only ascii text
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
} else {
@@ -220,12 +199,12 @@ public class PgpSignEncrypt {
ArmoredOutputStream armorOut = null;
OutputStream out;
- if (enableAsciiArmorOutput) {
- armorOut = new ArmoredOutputStream(outStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
+ if (mEnableAsciiArmorOutput) {
+ armorOut = new ArmoredOutputStream(mOutStream);
+ armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut;
} else {
- out = outStream;
+ out = mOutStream;
}
/* Get keys for signature generation for later usage */
@@ -233,25 +212,25 @@ public class PgpSignEncrypt {
PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null;
if (enableSignature) {
- signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
- signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
+ signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, mSignatureKeyId);
+ signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
if (signingKey == null) {
- throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
+ throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
- if (signaturePassphrase == null) {
+ if (mSignaturePassphrase == null) {
throw new PgpGeneralException(
- context.getString(R.string.error_no_signature_passphrase));
+ mContext.getString(R.string.error_no_signature_passphrase));
}
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
- context.getString(R.string.error_could_not_extract_private_key));
+ mContext.getString(R.string.error_could_not_extract_private_key));
}
}
updateProgress(R.string.progress_preparing_streams, 5, 100);
@@ -261,23 +240,23 @@ public class PgpSignEncrypt {
if (enableEncryption) {
// has Integrity packet enabled!
JcePGPDataEncryptorBuilder encryptorBuilder =
- new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm)
+ new JcePGPDataEncryptorBuilder(mSymmetricEncryptionAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
.setWithIntegrityPacket(true);
cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
- if (encryptionKeyIds.length == 0) {
+ if (mEncryptionKeyIds.length == 0) {
// Symmetric encryption
Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
- new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray());
+ new JcePBEKeyEncryptionMethodGenerator(mEncryptionPassphrase.toCharArray());
cPk.addMethod(symmetricEncryptionGenerator);
} else {
// Asymmetric encryption
- for (long id : encryptionKeyIds) {
- PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(context, id);
+ for (long id : mEncryptionKeyIds) {
+ PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
if (key != null) {
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
new JcePublicKeyKeyEncryptionMethodGenerator(key);
@@ -295,10 +274,10 @@ public class PgpSignEncrypt {
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
- signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
+ signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(signatureType, signaturePrivateKey);
} else {
@@ -322,14 +301,14 @@ public class PgpSignEncrypt {
encryptionOut = cPk.open(out, new byte[1 << 16]);
if (enableCompression) {
- compressGen = new PGPCompressedDataGenerator(compressionId);
+ compressGen = new PGPCompressedDataGenerator(mCompressionId);
bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
} else {
bcpgOut = new BCPGOutputStream(encryptionOut);
}
if (enableSignature) {
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
} else {
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
@@ -345,13 +324,13 @@ public class PgpSignEncrypt {
long progress = 0;
int n;
byte[] buffer = new byte[1 << 16];
- InputStream in = data.getInputStream();
+ InputStream in = mData.getInputStream();
while ((n = in.read(buffer)) > 0) {
pOut.write(buffer, 0, n);
// update signature buffer if signature is requested
if (enableSignature) {
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
signatureV3Generator.update(buffer, 0, n);
} else {
signatureGenerator.update(buffer, 0, n);
@@ -359,26 +338,26 @@ public class PgpSignEncrypt {
}
progress += n;
- if (data.getSize() != 0) {
- updateProgress((int) (20 + (95 - 20) * progress / data.getSize()), 100);
+ if (mData.getSize() != 0) {
+ updateProgress((int) (20 + (95 - 20) * progress / mData.getSize()), 100);
}
}
literalGen.close();
- } else if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
+ } else if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
/* sign-only of ascii text */
updateProgress(R.string.progress_signing, 40, 100);
// write directly on armor output stream
- armorOut.beginClearText(signatureHashAlgorithm);
+ armorOut.beginClearText(mSignatureHashAlgorithm);
- InputStream in = data.getInputStream();
+ InputStream in = mData.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
final byte[] newline = "\r\n".getBytes("UTF-8");
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
processLine(reader.readLine(), armorOut, signatureV3Generator);
} else {
processLine(reader.readLine(), armorOut, signatureGenerator);
@@ -395,7 +374,7 @@ public class PgpSignEncrypt {
armorOut.write(newline);
// update signature buffer with input line
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
signatureV3Generator.update(newline);
processLine(line, armorOut, signatureV3Generator);
} else {
@@ -415,7 +394,7 @@ public class PgpSignEncrypt {
if (enableSignature) {
updateProgress(R.string.progress_generating_signature, 95, 100);
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
signatureV3Generator.generate().encode(pOut);
} else {
signatureGenerator.generate().encode(pOut);
@@ -432,12 +411,12 @@ public class PgpSignEncrypt {
encryptionOut.close();
}
- if (enableAsciiArmorOutput) {
+ if (mEnableAsciiArmorOutput) {
armorOut.close();
}
out.close();
- outStream.close();
+ mOutStream.close();
updateProgress(R.string.progress_done, 100, 100);
}
@@ -449,35 +428,36 @@ public class PgpSignEncrypt {
SignatureException {
OutputStream out;
- if (enableAsciiArmorOutput) {
+ if (mEnableAsciiArmorOutput) {
// Ascii Armor (Radix-64)
- ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
+ ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
+ armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut;
} else {
- out = outStream;
+ out = mOutStream;
}
- if (signatureKeyId == 0) {
- throw new PgpGeneralException(context.getString(R.string.error_no_signature_key));
+ if (mSignatureKeyId == 0) {
+ throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
}
- PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
- PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
+ PGPSecretKeyRing signingKeyRing =
+ ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, mSignatureKeyId);
+ PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
if (signingKey == null) {
- throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
+ throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
- if (signaturePassphrase == null) {
- throw new PgpGeneralException(context.getString(R.string.error_no_signature_passphrase));
+ if (mSignaturePassphrase == null) {
+ throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
- context.getString(R.string.error_could_not_extract_private_key));
+ mContext.getString(R.string.error_could_not_extract_private_key));
}
updateProgress(R.string.progress_preparing_streams, 0, 100);
@@ -490,12 +470,12 @@ public class PgpSignEncrypt {
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
- .getPublicKey().getAlgorithm(), signatureHashAlgorithm)
+ .getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(type, signaturePrivateKey);
} else {
@@ -510,7 +490,7 @@ public class PgpSignEncrypt {
updateProgress(R.string.progress_signing, 40, 100);
- InputStream inStream = data.getInputStream();
+ InputStream inStream = mData.getInputStream();
// if (binary) {
// byte[] buffer = new byte[1 << 16];
// int n = 0;
@@ -527,7 +507,7 @@ public class PgpSignEncrypt {
String line;
while ((line = reader.readLine()) != null) {
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
processLine(line, null, signatureV3Generator);
signatureV3Generator.update(newline);
} else {
@@ -538,13 +518,13 @@ public class PgpSignEncrypt {
// }
BCPGOutputStream bOut = new BCPGOutputStream(out);
- if (signatureForceV3) {
+ if (mSignatureForceV3) {
signatureV3Generator.generate().encode(bOut);
} else {
signatureGenerator.generate().encode(bOut);
}
out.close();
- outStream.close();
+ mOutStream.close();
updateProgress(R.string.progress_done, 100, 100);
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java
index e18eb0d6d..54601173d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java
@@ -1,33 +1,24 @@
-package org.sufficientlysecure.keychain.pgp;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.SignatureException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.text.DateFormat;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Vector;
+/*
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * 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.
+ */
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
+package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.asn1.DERObjectIdentifier;
-import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
-import org.spongycastle.asn1.x509.BasicConstraints;
-import org.spongycastle.asn1.x509.GeneralName;
-import org.spongycastle.asn1.x509.GeneralNames;
-import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
-import org.spongycastle.asn1.x509.X509Extensions;
-import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.asn1.x509.*;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
@@ -38,30 +29,38 @@ import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Vector;
+
public class PgpToX509 {
- public final static String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge";
- public final static String DN_COMMON_PART_OU = "OpenPGP Keychain cert";
+ public static final String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge";
+ public static final String DN_COMMON_PART_OU = "OpenPGP Keychain cert";
/**
* Creates a self-signed certificate from a public and private key. The (critical) key-usage
* extension is set up with: digital signature, non-repudiation, key-encipherment, key-agreement
* and certificate-signing. The (non-critical) Netscape extension is set up with: SSL client and
* S/MIME. A URI subjectAltName may also be set up.
- *
- * @param pubKey
- * public key
- * @param privKey
- * private key
- * @param subject
- * subject (and issuer) DN for this certificate, RFC 2253 format preferred.
- * @param startDate
- * date from which the certificate will be valid (defaults to current date and time
- * if null)
- * @param endDate
- * date until which the certificate will be valid (defaults to current date and time
- * if null) *
- * @param subjAltNameURI
- * URI to be placed in subjectAltName
+ *
+ * @param pubKey public key
+ * @param privKey private key
+ * @param subject subject (and issuer) DN for this certificate, RFC 2253 format preferred.
+ * @param startDate date from which the certificate will be valid (defaults to current date and time
+ * if null)
+ * @param endDate date until which the certificate will be valid (defaults to current date and time
+ * if null) *
+ * @param subjAltNameURI URI to be placed in subjectAltName
* @return self-signed certificate
* @throws InvalidKeyException
* @throws SignatureException
@@ -70,11 +69,10 @@ public class PgpToX509 {
* @throws NoSuchProviderException
* @throws CertificateException
* @throws Exception
- *
* @author Bruno Harbulot
*/
public static X509Certificate createSelfSignedCert(PublicKey pubKey, PrivateKey privKey,
- X509Name subject, Date startDate, Date endDate, String subjAltNameURI)
+ X509Name subject, Date startDate, Date endDate, String subjAltNameURI)
throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException,
SignatureException, CertificateException, NoSuchProviderException {
@@ -171,15 +169,12 @@ public class PgpToX509 {
/**
* Creates a self-signed certificate from a PGP Secret Key.
- *
- * @param pgpSecKey
- * PGP Secret Key (from which one can extract the public and private keys and other
- * attributes).
- * @param pgpPrivKey
- * PGP Private Key corresponding to the Secret Key (password callbacks should be done
- * before calling this method)
- * @param subjAltNameURI
- * optional URI to embed in the subject alternative-name
+ *
+ * @param pgpSecKey PGP Secret Key (from which one can extract the public and private keys and other
+ * attributes).
+ * @param pgpPrivKey PGP Private Key corresponding to the Secret Key (password callbacks should be done
+ * before calling this method)
+ * @param subjAltNameURI optional URI to embed in the subject alternative-name
* @return self-signed certificate
* @throws PGPException
* @throws NoSuchProviderException
@@ -187,11 +182,10 @@ public class PgpToX509 {
* @throws NoSuchAlgorithmException
* @throws SignatureException
* @throws CertificateException
- *
* @author Bruno Harbulot
*/
public static X509Certificate createSelfSignedCert(PGPSecretKey pgpSecKey,
- PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException,
+ PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException,
NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException,
SignatureException, CertificateException {
// get public key from secret key
@@ -213,7 +207,7 @@ public class PgpToX509 {
x509NameValues.add(DN_COMMON_PART_OU);
for (@SuppressWarnings("unchecked")
- Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserIDs(); it.hasNext();) {
+ Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserIDs(); it.hasNext(); ) {
Object attrib = it.next();
x509NameOids.add(X509Name.CN);
x509NameValues.add("CryptoCall");
@@ -225,7 +219,7 @@ public class PgpToX509 {
*/
Log.d(Constants.TAG, "User attributes: ");
for (@SuppressWarnings("unchecked")
- Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserAttributes(); it.hasNext();) {
+ Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserAttributes(); it.hasNext(); ) {
Object attrib = it.next();
Log.d(Constants.TAG, " - " + attrib + " -- " + attrib.getClass());
}
@@ -261,14 +255,13 @@ public class PgpToX509 {
* This is a password callback handler that will fill in a password automatically. Useful to
* configure passwords in advance, but should be used with caution depending on how much you
* allow passwords to be stored within your application.
- *
+ *
* @author Bruno Harbulot.
- *
*/
- public final static class PredefinedPasswordCallbackHandler implements CallbackHandler {
+ public static final class PredefinedPasswordCallbackHandler implements CallbackHandler {
- private char[] password;
- private String prompt;
+ private char[] mPassword;
+ private String mPrompt;
public PredefinedPasswordCallbackHandler(String password) {
this(password == null ? null : password.toCharArray(), null);
@@ -283,16 +276,16 @@ public class PgpToX509 {
}
public PredefinedPasswordCallbackHandler(char[] password, String prompt) {
- this.password = password;
- this.prompt = prompt;
+ this.mPassword = password;
+ this.mPrompt = prompt;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof PasswordCallback) {
PasswordCallback pwCallback = (PasswordCallback) callback;
- if ((this.prompt == null) || (this.prompt.equals(pwCallback.getPrompt()))) {
- pwCallback.setPassword(this.password);
+ if ((this.mPrompt == null) || (this.mPrompt.equals(pwCallback.getPrompt()))) {
+ pwCallback.setPassword(this.mPassword);
}
} else {
throw new UnsupportedCallbackException(callback, "Unrecognised callback.");
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java
index 92542fa35..23c4bbbd9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * 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.pgp.exception;
public class NoAsymmetricEncryptionException extends Exception {
@@ -6,4 +23,4 @@ public class NoAsymmetricEncryptionException extends Exception {
public NoAsymmetricEncryptionException() {
super();
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
index 36c663727..bb80d27ee 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * 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.pgp.exception;
public class PgpGeneralException extends Exception {
@@ -6,4 +23,4 @@ public class PgpGeneralException extends Exception {
public PgpGeneralException(String message) {
super(message);
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
index d8de30b37..e7b31bf65 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
@@ -17,11 +17,11 @@
package org.sufficientlysecure.keychain.provider;
-import org.sufficientlysecure.keychain.Constants;
-
import android.net.Uri;
import android.provider.BaseColumns;
+import org.sufficientlysecure.keychain.Constants;
+
public class KeychainContract {
interface KeyRingsColumns {
@@ -57,10 +57,15 @@ public class KeychainContract {
interface ApiAppsColumns {
String PACKAGE_NAME = "package_name";
String PACKAGE_SIGNATURE = "package_signature";
+ }
+
+ interface ApiAppsAccountsColumns {
+ String ACCOUNT_NAME = "account_name";
String KEY_ID = "key_id"; // not a database id
String ENCRYPTION_ALGORITHM = "encryption_algorithm";
String HASH_ALORITHM = "hash_algorithm";
String COMPRESSION = "compression";
+ String PACKAGE_NAME = "package_name"; // foreign key to api_apps.package_name
}
public static final class KeyTypes {
@@ -88,18 +93,26 @@ public class KeychainContract {
public static final String PATH_KEYS = "keys";
public static final String BASE_API_APPS = "api_apps";
- public static final String PATH_BY_PACKAGE_NAME = "package_name";
+ public static final String PATH_ACCOUNTS = "accounts";
public static class KeyRings implements KeyRingsColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build();
- /** Use if multiple items get returned */
+ /**
+ * Use if multiple items get returned
+ */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key_ring";
- /** Use if a single item is returned */
+ /**
+ * Use if a single item is returned
+ */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key_ring";
+ public static Uri buildUnifiedKeyRingsUri() {
+ return CONTENT_URI;
+ }
+
public static Uri buildPublicKeyRingsUri() {
return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build();
}
@@ -147,6 +160,7 @@ public class KeychainContract {
}
public static Uri buildSecretKeyRingsByEmailsUri(String emails) {
+ // TODO: encoded?
return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(PATH_BY_EMAILS)
.appendPath(emails).build();
}
@@ -161,10 +175,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build();
- /** Use if multiple items get returned */
+ /**
+ * Use if multiple items get returned
+ */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key";
- /** Use if a single item is returned */
+ /**
+ * Use if a single item is returned
+ */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key";
public static Uri buildPublicKeysUri(String keyRingRowId) {
@@ -200,10 +218,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build();
- /** Use if multiple items get returned */
+ /**
+ * Use if multiple items get returned
+ */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.user_id";
- /** Use if a single item is returned */
+ /**
+ * Use if a single item is returned
+ */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.user_id";
public static Uri buildPublicUserIdsUri(String keyRingRowId) {
@@ -239,20 +261,44 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_API_APPS).build();
- /** Use if multiple items get returned */
+ /**
+ * Use if multiple items get returned
+ */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.api_apps";
- /** Use if a single item is returned */
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.api_apps";
+ /**
+ * Use if a single item is returned
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.api_app";
- public static Uri buildIdUri(String rowId) {
- return CONTENT_URI.buildUpon().appendPath(rowId).build();
+ public static Uri buildByPackageNameUri(String packageName) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build();
}
+ }
- public static Uri buildByPackageNameUri(String packageName) {
- return CONTENT_URI.buildUpon().appendPath(PATH_BY_PACKAGE_NAME).appendPath(packageName)
+ public static class ApiAccounts implements ApiAppsAccountsColumns, BaseColumns {
+ public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
+ .appendPath(BASE_API_APPS).build();
+
+ /**
+ * Use if multiple items get returned
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.api_app.accounts";
+
+ /**
+ * Use if a single item is returned
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.api_app.account";
+
+ public static Uri buildBaseUri(String packageName) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ACCOUNTS)
.build();
}
+
+ public static Uri buildByPackageAndAccountUri(String packageName, String accountName) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ACCOUNTS)
+ .appendEncodedPath(accountName).build();
+ }
}
public static class DataStream {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 5f18ed6f9..8c33844b2 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -17,27 +17,29 @@
package org.sufficientlysecure.keychain.provider;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.provider.BaseColumns;
+
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.provider.BaseColumns;
-
public class KeychainDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "apg.db";
- private static final int DATABASE_VERSION = 7;
+ private static final int DATABASE_VERSION = 8;
public interface Tables {
String KEY_RINGS = "key_rings";
String KEYS = "keys";
String USER_IDS = "user_ids";
String API_APPS = "api_apps";
+ String API_ACCOUNTS = "api_accounts";
}
private static final String CREATE_KEY_RINGS = "CREATE TABLE IF NOT EXISTS " + Tables.KEY_RINGS
@@ -62,26 +64,35 @@ public class KeychainDatabase extends SQLiteOpenHelper {
+ KeysColumns.KEY_DATA + " BLOB,"
+ KeysColumns.RANK + " INTEGER, "
+ KeysColumns.FINGERPRINT + " BLOB, "
- + KeysColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, FOREIGN KEY("
- + KeysColumns.KEY_RING_ROW_ID + ") REFERENCES " + Tables.KEY_RINGS + "("
- + BaseColumns._ID + ") ON DELETE CASCADE)";
+ + KeysColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, "
+ + "FOREIGN KEY(" + KeysColumns.KEY_RING_ROW_ID + ") REFERENCES "
+ + Tables.KEY_RINGS + "(" + BaseColumns._ID + ") ON DELETE CASCADE)";
private static final String CREATE_USER_IDS = "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS
+ " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ UserIdsColumns.USER_ID + " TEXT, "
+ UserIdsColumns.RANK + " INTEGER, "
- + UserIdsColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, FOREIGN KEY("
- + UserIdsColumns.KEY_RING_ROW_ID + ") REFERENCES " + Tables.KEY_RINGS + "("
- + BaseColumns._ID + ") ON DELETE CASCADE)";
+ + UserIdsColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, "
+ + "FOREIGN KEY(" + UserIdsColumns.KEY_RING_ROW_ID + ") REFERENCES "
+ + Tables.KEY_RINGS + "(" + BaseColumns._ID + ") ON DELETE CASCADE)";
private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS
+ " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, "
- + ApiAppsColumns.PACKAGE_SIGNATURE + " BLOB, "
- + ApiAppsColumns.KEY_ID + " INT64, "
- + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, "
- + ApiAppsColumns.HASH_ALORITHM + " INTEGER, "
- + ApiAppsColumns.COMPRESSION + " INTEGER)";
+ + ApiAppsColumns.PACKAGE_NAME + " TEXT NOT NULL UNIQUE, "
+ + ApiAppsColumns.PACKAGE_SIGNATURE + " BLOB)";
+
+ private static final String CREATE_API_APPS_ACCOUNTS = "CREATE TABLE IF NOT EXISTS " + Tables.API_ACCOUNTS
+ + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ApiAppsAccountsColumns.ACCOUNT_NAME + " TEXT NOT NULL, "
+ + ApiAppsAccountsColumns.KEY_ID + " INT64, "
+ + ApiAppsAccountsColumns.ENCRYPTION_ALGORITHM + " INTEGER, "
+ + ApiAppsAccountsColumns.HASH_ALORITHM + " INTEGER, "
+ + ApiAppsAccountsColumns.COMPRESSION + " INTEGER, "
+ + ApiAppsAccountsColumns.PACKAGE_NAME + " TEXT NOT NULL, "
+ + "UNIQUE(" + ApiAppsAccountsColumns.ACCOUNT_NAME + ", "
+ + ApiAppsAccountsColumns.PACKAGE_NAME + "), "
+ + "FOREIGN KEY(" + ApiAppsAccountsColumns.PACKAGE_NAME + ") REFERENCES "
+ + Tables.API_APPS + "(" + ApiAppsColumns.PACKAGE_NAME + ") ON DELETE CASCADE)";
KeychainDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -95,6 +106,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
db.execSQL(CREATE_KEYS);
db.execSQL(CREATE_USER_IDS);
db.execSQL(CREATE_API_APPS);
+ db.execSQL(CREATE_API_APPS_ACCOUNTS);
}
@Override
@@ -134,6 +146,12 @@ public class KeychainDatabase extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + Tables.KEYS + " ADD COLUMN " + KeysColumns.FINGERPRINT
+ " BLOB;");
break;
+ case 7:
+ // new db layout for api apps
+ db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS);
+ db.execSQL(CREATE_API_APPS);
+ db.execSQL(CREATE_API_APPS_ACCOUNTS);
+ break;
default:
break;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index 781f36758..1c5e3ab36 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,20 @@
package org.sufficientlysecure.keychain.provider;
-import java.util.Arrays;
-import java.util.HashMap;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteConstraintException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.text.TextUtils;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
@@ -32,17 +42,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.content.UriMatcher;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteConstraintException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.net.Uri;
-import android.provider.BaseColumns;
-import android.text.TextUtils;
+import java.util.Arrays;
+import java.util.HashMap;
public class KeychainProvider extends ContentProvider {
// public static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME
@@ -63,6 +64,7 @@ public class KeychainProvider extends ContentProvider {
private static final int PUBLIC_KEY_RING_USER_ID = 121;
private static final int PUBLIC_KEY_RING_USER_ID_BY_ROW_ID = 122;
+ private static final int PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID = 123;
private static final int SECRET_KEY_RING = 201;
private static final int SECRET_KEY_RING_BY_ROW_ID = 202;
@@ -78,8 +80,11 @@ public class KeychainProvider extends ContentProvider {
private static final int SECRET_KEY_RING_USER_ID_BY_ROW_ID = 222;
private static final int API_APPS = 301;
- private static final int API_APPS_BY_ROW_ID = 302;
private static final int API_APPS_BY_PACKAGE_NAME = 303;
+ private static final int API_ACCOUNTS = 304;
+ private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306;
+
+ private static final int UNIFIED_KEY_RING = 401;
// private static final int DATA_STREAM = 401;
@@ -95,6 +100,15 @@ public class KeychainProvider extends ContentProvider {
String authority = KeychainContract.CONTENT_AUTHORITY;
/**
+ * unified key rings
+ *
+ * <pre>
+ * key_rings
+ * </pre>
+ */
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS, UNIFIED_KEY_RING);
+
+ /**
* public key rings
*
* <pre>
@@ -147,6 +161,7 @@ public class KeychainProvider extends ContentProvider {
* <pre>
* key_rings/public/#/user_ids
* key_rings/public/#/user_ids/#
+ * key_rings/public/master_key_id/#/user_ids
* </pre>
*/
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
@@ -155,6 +170,10 @@ public class KeychainProvider extends ContentProvider {
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_USER_IDS + "/#",
PUBLIC_KEY_RING_USER_ID_BY_ROW_ID);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ + KeychainContract.PATH_PUBLIC + "/"
+ + KeychainContract.PATH_BY_MASTER_KEY_ID + "/*/" + KeychainContract.PATH_USER_IDS,
+ PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID);
/**
* secret key rings
@@ -220,11 +239,22 @@ public class KeychainProvider extends ContentProvider {
/**
* API apps
+ *
+ * <pre>
+ * api_apps
+ * api_apps/_ (package name)
+ *
+ * api_apps/_/accounts
+ * api_apps/_/accounts/_ (account name)
+ * </pre>
*/
matcher.addURI(authority, KeychainContract.BASE_API_APPS, API_APPS);
- matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/#", API_APPS_BY_ROW_ID);
- matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/"
- + KeychainContract.PATH_BY_PACKAGE_NAME + "/*", API_APPS_BY_PACKAGE_NAME);
+ matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME);
+
+ matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
+ + KeychainContract.PATH_ACCOUNTS, API_ACCOUNTS);
+ matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
+ + KeychainContract.PATH_ACCOUNTS + "/*", API_ACCOUNTS_BY_ACCOUNT_NAME);
/**
* data stream
@@ -238,7 +268,7 @@ public class KeychainProvider extends ContentProvider {
return matcher;
}
- private KeychainDatabase mApgDatabase;
+ private KeychainDatabase mKeychainDatabase;
/**
* {@inheritDoc}
@@ -246,7 +276,7 @@ public class KeychainProvider extends ContentProvider {
@Override
public boolean onCreate() {
mUriMatcher = buildUriMatcher();
- mApgDatabase = new KeychainDatabase(getContext());
+ mKeychainDatabase = new KeychainDatabase(getContext());
return true;
}
@@ -282,6 +312,7 @@ public class KeychainProvider extends ContentProvider {
return Keys.CONTENT_ITEM_TYPE;
case PUBLIC_KEY_RING_USER_ID:
+ case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
case SECRET_KEY_RING_USER_ID:
return UserIds.CONTENT_TYPE;
@@ -292,10 +323,15 @@ public class KeychainProvider extends ContentProvider {
case API_APPS:
return ApiApps.CONTENT_TYPE;
- case API_APPS_BY_ROW_ID:
case API_APPS_BY_PACKAGE_NAME:
return ApiApps.CONTENT_ITEM_TYPE;
+ case API_ACCOUNTS:
+ return ApiAccounts.CONTENT_TYPE;
+
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ return ApiAccounts.CONTENT_ITEM_TYPE;
+
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
@@ -304,7 +340,7 @@ public class KeychainProvider extends ContentProvider {
/**
* Returns type of the query (secret/public)
*
- * @param uri
+ * @param match
* @return
*/
private int getKeyType(int match) {
@@ -319,6 +355,7 @@ public class KeychainProvider extends ContentProvider {
case PUBLIC_KEY_RING_KEY:
case PUBLIC_KEY_RING_KEY_BY_ROW_ID:
case PUBLIC_KEY_RING_USER_ID:
+ case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID:
type = KeyTypes.PUBLIC;
break;
@@ -356,15 +393,25 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID);
projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "."
+ KeyRingsColumns.KEY_RING_DATA);
- projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID);
+ projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
+ + KeyRingsColumns.MASTER_KEY_ID);
// TODO: deprecated master key id
//projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.KEY_ID);
+ projectionMap.put(KeysColumns.ALGORITHM, Tables.KEYS + "." + KeysColumns.ALGORITHM);
+ projectionMap.put(KeysColumns.KEY_SIZE, Tables.KEYS + "." + KeysColumns.KEY_SIZE);
+ projectionMap.put(KeysColumns.CREATION, Tables.KEYS + "." + KeysColumns.CREATION);
+ projectionMap.put(KeysColumns.EXPIRY, Tables.KEYS + "." + KeysColumns.EXPIRY);
+ projectionMap.put(KeysColumns.KEY_RING_ROW_ID, Tables.KEYS + "." + KeysColumns.KEY_RING_ROW_ID);
projectionMap.put(KeysColumns.FINGERPRINT, Tables.KEYS + "." + KeysColumns.FINGERPRINT);
projectionMap.put(KeysColumns.IS_REVOKED, Tables.KEYS + "." + KeysColumns.IS_REVOKED);
projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID);
+ // type attribute is special: if there is any grouping, choose secret over public type
+ projectionMap.put(KeyRingsColumns.TYPE,
+ "MAX(" + Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + ") AS " + KeyRingsColumns.TYPE);
+
return projectionMap;
}
@@ -395,13 +442,27 @@ public class KeychainProvider extends ContentProvider {
return projectionMap;
}
+ private HashMap<String, String> getProjectionMapForUserIds() {
+ HashMap<String, String> projectionMap = new HashMap<String, String>();
+
+ projectionMap.put(BaseColumns._ID, Tables.USER_IDS + "." + BaseColumns._ID);
+ projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID);
+ projectionMap.put(UserIdsColumns.RANK, Tables.USER_IDS + "." + UserIdsColumns.RANK);
+ projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
+ + KeyRingsColumns.MASTER_KEY_ID);
+
+ return projectionMap;
+ }
+
/**
* Builds default query for keyRings: KeyRings table is joined with UserIds and Keys
*/
private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match) {
- // public or secret keyring
- qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = ");
- qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
+ if (match != UNIFIED_KEY_RING) {
+ // public or secret keyring
+ qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = ");
+ qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
+ }
// join keyrings with keys and userIds
// Only get user id and key with rank 0 (main user id and main key)
@@ -451,11 +512,26 @@ public class KeychainProvider extends ContentProvider {
Log.v(Constants.TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- SQLiteDatabase db = mApgDatabase.getReadableDatabase();
+ SQLiteDatabase db = mKeychainDatabase.getReadableDatabase();
int match = mUriMatcher.match(uri);
+ // all query() parameters, for good measure
+ String groupBy = null, having = null;
+
switch (match) {
+ case UNIFIED_KEY_RING:
+ qb = buildKeyRingQuery(qb, match);
+
+ // GROUP BY so we don't get duplicates
+ groupBy = Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID;
+
+ if (TextUtils.isEmpty(sortOrder)) {
+ sortOrder = KeyRings.TYPE + " DESC, " +
+ Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
+ }
+
+ break;
case PUBLIC_KEY_RING:
case SECRET_KEY_RING:
qb = buildKeyRingQuery(qb, match);
@@ -465,7 +541,6 @@ public class KeychainProvider extends ContentProvider {
}
break;
-
case PUBLIC_KEY_RING_BY_ROW_ID:
case SECRET_KEY_RING_BY_ROW_ID:
qb = buildKeyRingQuery(qb, match);
@@ -478,7 +553,6 @@ public class KeychainProvider extends ContentProvider {
}
break;
-
case PUBLIC_KEY_RING_BY_MASTER_KEY_ID:
case SECRET_KEY_RING_BY_MASTER_KEY_ID:
qb = buildKeyRingQuery(qb, match);
@@ -491,7 +565,6 @@ public class KeychainProvider extends ContentProvider {
}
break;
-
case SECRET_KEY_RING_BY_KEY_ID:
case PUBLIC_KEY_RING_BY_KEY_ID:
qb = buildKeyRingQueryWithSpecificKey(qb, match);
@@ -504,7 +577,6 @@ public class KeychainProvider extends ContentProvider {
}
break;
-
case SECRET_KEY_RING_BY_EMAILS:
case PUBLIC_KEY_RING_BY_EMAILS:
qb = buildKeyRingQuery(qb, match);
@@ -534,7 +606,6 @@ public class KeychainProvider extends ContentProvider {
}
break;
-
case SECRET_KEY_RING_BY_LIKE_EMAIL:
case PUBLIC_KEY_RING_BY_LIKE_EMAIL:
qb = buildKeyRingQuery(qb, match);
@@ -550,7 +621,6 @@ public class KeychainProvider extends ContentProvider {
+ "))");
break;
-
case PUBLIC_KEY_RING_KEY:
case SECRET_KEY_RING_KEY:
qb.setTables(Tables.KEYS);
@@ -563,7 +633,6 @@ public class KeychainProvider extends ContentProvider {
qb.setProjectionMap(getProjectionMapForKeys());
break;
-
case PUBLIC_KEY_RING_KEY_BY_ROW_ID:
case SECRET_KEY_RING_KEY_BY_ROW_ID:
qb.setTables(Tables.KEYS);
@@ -579,7 +648,16 @@ public class KeychainProvider extends ContentProvider {
qb.setProjectionMap(getProjectionMapForKeys());
break;
+ case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
+ qb.setTables(Tables.USER_IDS + " INNER JOIN " + Tables.KEY_RINGS + " ON " + "("
+ + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.USER_IDS + "."
+ + KeysColumns.KEY_RING_ROW_ID + " )");
+ qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(3));
+
+ qb.setProjectionMap(getProjectionMapForUserIds());
+ break;
case PUBLIC_KEY_RING_USER_ID:
case SECRET_KEY_RING_USER_ID:
qb.setTables(Tables.USER_IDS);
@@ -587,7 +665,6 @@ public class KeychainProvider extends ContentProvider {
qb.appendWhereEscapeString(uri.getPathSegments().get(2));
break;
-
case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID:
case SECRET_KEY_RING_USER_ID_BY_ROW_ID:
qb.setTables(Tables.USER_IDS);
@@ -598,25 +675,31 @@ public class KeychainProvider extends ContentProvider {
qb.appendWhereEscapeString(uri.getLastPathSegment());
break;
-
case API_APPS:
qb.setTables(Tables.API_APPS);
break;
- case API_APPS_BY_ROW_ID:
+ case API_APPS_BY_PACKAGE_NAME:
qb.setTables(Tables.API_APPS);
-
- qb.appendWhere(BaseColumns._ID + " = ");
+ qb.appendWhere(ApiApps.PACKAGE_NAME + " = ");
qb.appendWhereEscapeString(uri.getLastPathSegment());
break;
- case API_APPS_BY_PACKAGE_NAME:
- qb.setTables(Tables.API_APPS);
- qb.appendWhere(ApiApps.PACKAGE_NAME + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(2));
+ case API_ACCOUNTS:
+ qb.setTables(Tables.API_ACCOUNTS);
+ qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break;
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ qb.setTables(Tables.API_ACCOUNTS);
+ qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
+ qb.appendWhere(" AND " + Tables.API_ACCOUNTS + "." + ApiAccounts.ACCOUNT_NAME + " = ");
+ qb.appendWhereEscapeString(uri.getLastPathSegment());
+
+ break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
@@ -630,7 +713,7 @@ public class KeychainProvider extends ContentProvider {
orderBy = sortOrder;
}
- Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
+ Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
// Tell the cursor what uri to watch, so it knows when its source data changes
c.setNotificationUri(getContext().getContentResolver(), uri);
@@ -653,7 +736,7 @@ public class KeychainProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")");
- final SQLiteDatabase db = mApgDatabase.getWritableDatabase();
+ final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
Uri rowUri = null;
long rowId = -1;
@@ -673,12 +756,14 @@ public class KeychainProvider extends ContentProvider {
values.put(Keys.TYPE, KeyTypes.PUBLIC);
rowId = db.insertOrThrow(Tables.KEYS, null, values);
+ // TODO: this is wrong:
rowUri = Keys.buildPublicKeysUri(Long.toString(rowId));
sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
break;
case PUBLIC_KEY_RING_USER_ID:
rowId = db.insertOrThrow(Tables.USER_IDS, null, values);
+ // TODO: this is wrong:
rowUri = UserIds.buildPublicUserIdsUri(Long.toString(rowId));
sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
@@ -695,18 +780,33 @@ public class KeychainProvider extends ContentProvider {
values.put(Keys.TYPE, KeyTypes.SECRET);
rowId = db.insertOrThrow(Tables.KEYS, null, values);
+ // TODO: this is wrong:
rowUri = Keys.buildSecretKeysUri(Long.toString(rowId));
sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
break;
case SECRET_KEY_RING_USER_ID:
rowId = db.insertOrThrow(Tables.USER_IDS, null, values);
+ // TODO: this is wrong:
rowUri = UserIds.buildSecretUserIdsUri(Long.toString(rowId));
break;
case API_APPS:
rowId = db.insertOrThrow(Tables.API_APPS, null, values);
- rowUri = ApiApps.buildIdUri(Long.toString(rowId));
+// rowUri = ApiApps.buildIdUri(Long.toString(rowId));
+
+ break;
+ case API_ACCOUNTS:
+ // set foreign key automatically based on given uri
+ // e.g., api_apps/com.example.app/accounts/
+ String packageName = uri.getPathSegments().get(1);
+ values.put(ApiAccounts.PACKAGE_NAME, packageName);
+
+ Log.d(Constants.TAG, "provider packageName: " + packageName);
+
+ rowId = db.insertOrThrow(Tables.API_ACCOUNTS, null, values);
+ // TODO: this is wrong:
+// rowUri = ApiAccounts.buildIdUri(Long.toString(rowId));
break;
default:
@@ -730,7 +830,7 @@ public class KeychainProvider extends ContentProvider {
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.v(Constants.TAG, "delete(uri=" + uri + ")");
- final SQLiteDatabase db = mApgDatabase.getWritableDatabase();
+ final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
int count;
final int match = mUriMatcher.match(uri);
@@ -766,12 +866,12 @@ public class KeychainProvider extends ContentProvider {
count = db.delete(Tables.KEYS, buildDefaultUserIdsSelection(uri, selection),
selectionArgs);
break;
- case API_APPS_BY_ROW_ID:
- count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, false, selection),
+ case API_APPS_BY_PACKAGE_NAME:
+ count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, selection),
selectionArgs);
break;
- case API_APPS_BY_PACKAGE_NAME:
- count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, true, selection),
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, selection),
selectionArgs);
break;
default:
@@ -791,7 +891,7 @@ public class KeychainProvider extends ContentProvider {
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.v(Constants.TAG, "update(uri=" + uri + ", values=" + values.toString() + ")");
- final SQLiteDatabase db = mApgDatabase.getWritableDatabase();
+ final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
String defaultSelection = null;
int count = 0;
@@ -836,13 +936,13 @@ public class KeychainProvider extends ContentProvider {
count = db.update(Tables.USER_IDS, values,
buildDefaultUserIdsSelection(uri, selection), selectionArgs);
break;
- case API_APPS_BY_ROW_ID:
- count = db.update(Tables.API_APPS, values,
- buildDefaultApiAppsSelection(uri, false, selection), selectionArgs);
- break;
case API_APPS_BY_PACKAGE_NAME:
count = db.update(Tables.API_APPS, values,
- buildDefaultApiAppsSelection(uri, true, selection), selectionArgs);
+ buildDefaultApiAppsSelection(uri, selection), selectionArgs);
+ break;
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ count = db.update(Tables.API_ACCOUNTS, values,
+ buildDefaultApiAccountsSelection(uri, selection), selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
@@ -862,7 +962,8 @@ public class KeychainProvider extends ContentProvider {
* Build default selection statement for KeyRings. If no extra selection is specified only build
* where clause with rowId
*
- * @param uri
+ * @param defaultSelection
+ * @param keyType
* @param selection
* @return
*/
@@ -940,19 +1041,29 @@ public class KeychainProvider extends ContentProvider {
* @param selection
* @return
*/
- private String buildDefaultApiAppsSelection(Uri uri, boolean packageSelection, String selection) {
- String lastPathSegment = uri.getLastPathSegment();
+ private String buildDefaultApiAppsSelection(Uri uri, String selection) {
+ String packageName = DatabaseUtils.sqlEscapeString(uri.getLastPathSegment());
String andSelection = "";
if (!TextUtils.isEmpty(selection)) {
andSelection = " AND (" + selection + ")";
}
- if (packageSelection) {
- return ApiApps.PACKAGE_NAME + "=" + lastPathSegment + andSelection;
- } else {
- return BaseColumns._ID + "=" + lastPathSegment + andSelection;
+ return ApiApps.PACKAGE_NAME + "=" + packageName + andSelection;
+ }
+
+ private String buildDefaultApiAccountsSelection(Uri uri, String selection) {
+ String packageName = DatabaseUtils.sqlEscapeString(uri.getPathSegments().get(1));
+ String accountName = DatabaseUtils.sqlEscapeString(uri.getLastPathSegment());
+
+ String andSelection = "";
+ if (!TextUtils.isEmpty(selection)) {
+ andSelection = " AND (" + selection + ")";
}
+
+ return ApiAccounts.PACKAGE_NAME + "=" + packageName + " AND "
+ + ApiAccounts.ACCOUNT_NAME + "=" + accountName
+ + andSelection;
}
// @Override
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java
index a879d60a8..701ffc6af 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java
@@ -17,10 +17,9 @@
package org.sufficientlysecure.keychain.provider;
-import org.sufficientlysecure.keychain.Constants;
-
import android.net.Uri;
import android.provider.BaseColumns;
+import org.sufficientlysecure.keychain.Constants;
public class KeychainServiceBlobContract {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java
index fcee76fd7..da1bcb2d9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java
@@ -22,7 +22,6 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
-
import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns;
public class KeychainServiceBlobDatabase extends SQLiteOpenHelper {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java
index 5693e6de2..aa30e845d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java
@@ -18,11 +18,6 @@
package org.sufficientlysecure.keychain.provider;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.Blobs;
-import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -31,7 +26,10 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
-
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.Blobs;
+import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns;
+import org.sufficientlysecure.keychain.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
@@ -40,7 +38,7 @@ import java.util.List;
import java.util.UUID;
public class KeychainServiceBlobProvider extends ContentProvider {
- private static final String STORE_PATH = Constants.path.APP_DIR + "/ApgBlobs";
+ private static final String STORE_PATH = Constants.Path.APP_DIR + "/KeychainBlobs";
private KeychainServiceBlobDatabase mBlobDatabase = null;
@@ -55,7 +53,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return true;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
public Uri insert(Uri uri, ContentValues ignored) {
// ContentValues are actually ignored, because we want to store a blob with no more
@@ -74,7 +74,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return Uri.withAppendedPath(insertedUri, password);
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException,
FileNotFoundException {
@@ -91,9 +93,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
// get the data
SQLiteDatabase db = mBlobDatabase.getReadableDatabase();
- Cursor result = db.query(KeychainServiceBlobDatabase.TABLE, new String[] { BaseColumns._ID },
+ Cursor result = db.query(KeychainServiceBlobDatabase.TABLE, new String[]{BaseColumns._ID},
BaseColumns._ID + " = ? and " + BlobsColumns.KEY + " = ?",
- new String[] { id, key }, null, null, null);
+ new String[]{id, key}, null, null, null);
if (result.getCount() == 0) {
// either the key is wrong or no id exists
@@ -124,26 +126,34 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return null;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
public String getType(Uri uri) {
return null;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
+ String sortOrder) {
return null;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index fef3d391b..b47c4946f 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -17,10 +17,11 @@
package org.sufficientlysecure.keychain.provider;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
+import android.content.*;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.net.Uri;
+import android.os.RemoteException;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.openpgp.PGPKeyRing;
@@ -38,19 +39,15 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
-import org.sufficientlysecure.keychain.service.remote.AppSettings;
+import org.sufficientlysecure.keychain.remote.AccountSettings;
+import org.sufficientlysecure.keychain.remote.AppSettings;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.ContentProviderOperation;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.OperationApplicationException;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.net.Uri;
-import android.os.RemoteException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
public class ProviderHelper {
@@ -87,7 +84,7 @@ public class ProviderHelper {
}
/**
- * Retrieves the actual PGPPublicKeyRing object from the database blob based on the maserKeyId
+ * Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId
*/
public static PGPPublicKeyRing getPGPPublicKeyRingByMasterKeyId(Context context,
long masterKeyId) {
@@ -110,11 +107,8 @@ public class ProviderHelper {
*/
public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) {
PGPPublicKeyRing keyRing = getPGPPublicKeyRingByKeyId(context, keyId);
- if (keyRing == null) {
- return null;
- }
- return keyRing.getPublicKey(keyId);
+ return (keyRing == null) ? null : keyRing.getPublicKey(keyId);
}
/**
@@ -149,11 +143,8 @@ public class ProviderHelper {
*/
public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) {
PGPSecretKeyRing keyRing = getPGPSecretKeyRingByKeyId(context, keyId);
- if (keyRing == null) {
- return null;
- }
- return keyRing.getSecretKey(keyId);
+ return (keyRing == null) ? null : keyRing.getSecretKey(keyId);
}
/**
@@ -168,7 +159,8 @@ public class ProviderHelper {
// get current _ID of key
long currentRowId = -1;
- Cursor oldQuery = context.getContentResolver().query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
+ Cursor oldQuery = context.getContentResolver()
+ .query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
if (oldQuery != null && oldQuery.moveToFirst()) {
currentRowId = oldQuery.getLong(0);
} else {
@@ -184,10 +176,12 @@ public class ProviderHelper {
ContentValues values = new ContentValues();
// use exactly the same _ID again to replace key in-place.
- // NOTE: If we would not use the same _ID again, getting back to the ViewKeyActivity would result in Nullpointer,
+ // NOTE: If we would not use the same _ID again,
+ // getting back to the ViewKeyActivity would result in Nullpointer,
// because the currently loaded key would be gone from the database
- if (currentRowId != -1)
+ if (currentRowId != -1) {
values.put(KeyRings._ID, currentRowId);
+ }
values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
@@ -211,8 +205,11 @@ public class ProviderHelper {
++userIdRank;
}
- for (PGPSignature certification : new IterableIterator<PGPSignature>(masterKey.getSignaturesOfType(PGPSignature.POSITIVE_CERTIFICATION))) {
- //TODO: how to do this?? we need to verify the signatures again and again when they are displayed...
+ for (PGPSignature certification :
+ new IterableIterator<PGPSignature>(
+ masterKey.getSignaturesOfType(PGPSignature.POSITIVE_CERTIFICATION))) {
+ // TODO: how to do this??
+ // we need to verify the signatures again and again when they are displayed...
// if (certification.verify
// operations.add(buildPublicKeyOperations(context, keyRingRowId, key, rank));
}
@@ -239,7 +236,8 @@ public class ProviderHelper {
// get current _ID of key
long currentRowId = -1;
- Cursor oldQuery = context.getContentResolver().query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
+ Cursor oldQuery = context.getContentResolver()
+ .query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
if (oldQuery != null && oldQuery.moveToFirst()) {
currentRowId = oldQuery.getLong(0);
} else {
@@ -255,10 +253,12 @@ public class ProviderHelper {
ContentValues values = new ContentValues();
// use exactly the same _ID again to replace key in-place.
- // NOTE: If we would not use the same _ID again, getting back to the ViewKeyActivity would result in Nullpointer,
+ // NOTE: If we would not use the same _ID again,
+ // getting back to the ViewKeyActivity would result in Nullpointer,
// because the currently loaded key would be gone from the database
- if (currentRowId != -1)
+ if (currentRowId != -1) {
values.put(KeyRings._ID, currentRowId);
+ }
values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
@@ -341,10 +341,10 @@ public class ProviderHelper {
long keyRingRowId, PGPSecretKey key, int rank) throws IOException {
ContentValues values = new ContentValues();
- boolean has_private = true;
+ boolean hasPrivate = true;
if (key.isMasterKey()) {
- if (PgpKeyHelper.isSecretKeyPrivateEmpty(key)) {
- has_private = false;
+ if (key.isPrivateKeyEmpty()) {
+ hasPrivate = false;
}
}
@@ -352,9 +352,9 @@ public class ProviderHelper {
values.put(Keys.IS_MASTER_KEY, key.isMasterKey());
values.put(Keys.ALGORITHM, key.getPublicKey().getAlgorithm());
values.put(Keys.KEY_SIZE, key.getPublicKey().getBitStrength());
- values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key) && has_private));
- values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key) && has_private));
- values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key) && has_private);
+ values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key) && hasPrivate));
+ values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key) && hasPrivate));
+ values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key) && hasPrivate);
values.put(Keys.IS_REVOKED, key.getPublicKey().isRevoked());
values.put(Keys.CREATION, PgpKeyHelper.getCreationDate(key).getTime() / 1000);
Date expiryDate = PgpKeyHelper.getExpiryDate(key);
@@ -411,6 +411,30 @@ public class ProviderHelper {
}
/**
+ * Private helper method
+ */
+ private static ArrayList<Long> getKeyRingsRowIds(Context context, Uri queryUri) {
+ Cursor cursor = context.getContentResolver().query(queryUri,
+ new String[]{KeyRings._ID}, null, null, null);
+
+ ArrayList<Long> rowIds = new ArrayList<Long>();
+ if (cursor != null) {
+ int idCol = cursor.getColumnIndex(KeyRings._ID);
+ if (cursor.moveToFirst()) {
+ do {
+ rowIds.add(cursor.getLong(idCol));
+ } while (cursor.moveToNext());
+ }
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return rowIds;
+ }
+
+ /**
* Retrieves ids of all SecretKeyRings
*/
public static ArrayList<Long> getSecretKeyRingsMasterKeyIds(Context context) {
@@ -426,6 +450,22 @@ public class ProviderHelper {
return getKeyRingsMasterKeyIds(context, queryUri);
}
+ /**
+ * Retrieves ids of all SecretKeyRings
+ */
+ public static ArrayList<Long> getSecretKeyRingsRowIds(Context context) {
+ Uri queryUri = KeyRings.buildSecretKeyRingsUri();
+ return getKeyRingsRowIds(context, queryUri);
+ }
+
+ /**
+ * Retrieves ids of all PublicKeyRings
+ */
+ public static ArrayList<Long> getPublicKeyRingsRowIds(Context context) {
+ Uri queryUri = KeyRings.buildPublicKeyRingsUri();
+ return getKeyRingsRowIds(context, queryUri);
+ }
+
public static void deletePublicKeyRing(Context context, long rowId) {
ContentResolver cr = context.getContentResolver();
cr.delete(KeyRings.buildPublicKeyRingsUri(Long.toString(rowId)), null, null);
@@ -436,6 +476,15 @@ public class ProviderHelper {
cr.delete(KeyRings.buildSecretKeyRingsUri(Long.toString(rowId)), null, null);
}
+ public static void deleteUnifiedKeyRing(Context context, String masterKeyId, boolean isSecretKey) {
+ ContentResolver cr = context.getContentResolver();
+ cr.delete(KeyRings.buildPublicKeyRingsByMasterKeyIdUri(masterKeyId), null, null);
+ if (isSecretKey) {
+ cr.delete(KeyRings.buildSecretKeyRingsByMasterKeyIdUri(masterKeyId), null, null);
+ }
+
+ }
+
/**
* Get master key id of keyring by its row id
*/
@@ -449,13 +498,14 @@ public class ProviderHelper {
*/
public static boolean getSecretMasterKeyCanCertify(Context context, long keyRingRowId) {
Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId));
- return getMasterKeyCanCertify(context, queryUri, keyRingRowId);
+ return getMasterKeyCanCertify(context, queryUri);
}
/**
* Private helper method to get master key private empty status of keyring by its row id
*/
- private static boolean getMasterKeyCanCertify(Context context, Uri queryUri, long keyRingRowId) {
+
+ public static boolean getMasterKeyCanCertify(Context context, Uri queryUri) {
String[] projection = new String[]{
KeyRings.MASTER_KEY_ID,
"(SELECT COUNT(sign_keys." + Keys._ID + ") FROM " + Tables.KEYS
@@ -481,6 +531,12 @@ public class ProviderHelper {
return (masterKeyId > 0);
}
+ public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) {
+ Uri queryUri = KeyRings.buildSecretKeyRingsByMasterKeyIdUri(Long.toString(masterKeyId));
+ // see if we can get our master key id back from the uri
+ return getMasterKeyId(context, queryUri) == masterKeyId;
+ }
+
/**
* Get master key id of keyring by its row id
*/
@@ -512,6 +568,26 @@ public class ProviderHelper {
return masterKeyId;
}
+ public static long getRowId(Context context, Uri queryUri) {
+ String[] projection = new String[]{KeyRings._ID};
+ Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
+
+ long rowId = 0;
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ int idCol = cursor.getColumnIndexOrThrow(KeyRings._ID);
+
+ rowId = cursor.getLong(idCol);
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return rowId;
+ }
+
/**
* Get fingerprint of key
*/
@@ -733,19 +809,28 @@ public class ProviderHelper {
ContentValues values = new ContentValues();
values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName());
values.put(ApiApps.PACKAGE_SIGNATURE, appSettings.getPackageSignature());
- values.put(ApiApps.KEY_ID, appSettings.getKeyId());
- values.put(ApiApps.COMPRESSION, appSettings.getCompression());
- values.put(ApiApps.ENCRYPTION_ALGORITHM, appSettings.getEncryptionAlgorithm());
- values.put(ApiApps.HASH_ALORITHM, appSettings.getHashAlgorithm());
+ return values;
+ }
+ private static ContentValues contentValueForApiAccounts(AccountSettings accSettings) {
+ ContentValues values = new ContentValues();
+ values.put(KeychainContract.ApiAccounts.ACCOUNT_NAME, accSettings.getAccountName());
+ values.put(KeychainContract.ApiAccounts.KEY_ID, accSettings.getKeyId());
+ values.put(KeychainContract.ApiAccounts.COMPRESSION, accSettings.getCompression());
+ values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM, accSettings.getEncryptionAlgorithm());
+ values.put(KeychainContract.ApiAccounts.HASH_ALORITHM, accSettings.getHashAlgorithm());
return values;
}
public static void insertApiApp(Context context, AppSettings appSettings) {
- context.getContentResolver().insert(ApiApps.CONTENT_URI,
+ context.getContentResolver().insert(KeychainContract.ApiApps.CONTENT_URI,
contentValueForApiApps(appSettings));
}
+ public static void insertApiAccount(Context context, Uri uri, AccountSettings accSettings) {
+ context.getContentResolver().insert(uri, contentValueForApiAccounts(accSettings));
+ }
+
public static void updateApiApp(Context context, AppSettings appSettings, Uri uri) {
if (context.getContentResolver().update(uri, contentValueForApiApps(appSettings), null,
null) <= 0) {
@@ -753,30 +838,59 @@ public class ProviderHelper {
}
}
+ public static void updateApiAccount(Context context, AccountSettings accSettings, Uri uri) {
+ if (context.getContentResolver().update(uri, contentValueForApiAccounts(accSettings), null,
+ null) <= 0) {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Must be an uri pointing to an account
+ *
+ * @param context
+ * @param uri
+ * @return
+ */
public static AppSettings getApiAppSettings(Context context, Uri uri) {
AppSettings settings = null;
Cursor cur = context.getContentResolver().query(uri, null, null, null, null);
if (cur != null && cur.moveToFirst()) {
settings = new AppSettings();
- settings.setPackageName(cur.getString(cur
- .getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME)));
- settings.setPackageSignature(cur.getBlob(cur
- .getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE)));
- settings.setKeyId(cur.getLong(cur.getColumnIndex(KeychainContract.ApiApps.KEY_ID)));
- settings.setCompression(cur.getInt(cur
- .getColumnIndexOrThrow(KeychainContract.ApiApps.COMPRESSION)));
- settings.setHashAlgorithm(cur.getInt(cur
- .getColumnIndexOrThrow(KeychainContract.ApiApps.HASH_ALORITHM)));
- settings.setEncryptionAlgorithm(cur.getInt(cur
- .getColumnIndexOrThrow(KeychainContract.ApiApps.ENCRYPTION_ALGORITHM)));
+ settings.setPackageName(cur.getString(
+ cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME)));
+ settings.setPackageSignature(cur.getBlob(
+ cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE)));
+ }
+
+ return settings;
+ }
+
+ public static AccountSettings getApiAccountSettings(Context context, Uri uri) {
+ AccountSettings settings = null;
+
+ Cursor cur = context.getContentResolver().query(uri, null, null, null, null);
+ if (cur != null && cur.moveToFirst()) {
+ settings = new AccountSettings();
+
+ settings.setAccountName(cur.getString(
+ cur.getColumnIndex(KeychainContract.ApiAccounts.ACCOUNT_NAME)));
+ settings.setKeyId(cur.getLong(
+ cur.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID)));
+ settings.setCompression(cur.getInt(
+ cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.COMPRESSION)));
+ settings.setHashAlgorithm(cur.getInt(
+ cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.HASH_ALORITHM)));
+ settings.setEncryptionAlgorithm(cur.getInt(
+ cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM)));
}
return settings;
}
public static byte[] getApiAppSignature(Context context, String packageName) {
- Uri queryUri = KeychainContract.ApiApps.buildByPackageNameUri(packageName);
+ Uri queryUri = ApiApps.buildByPackageNameUri(packageName);
String[] projection = new String[]{ApiApps.PACKAGE_SIGNATURE};
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettings.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AccountSettings.java
index 9da4c8392..832cbc752 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettings.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AccountSettings.java
@@ -15,80 +15,71 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.service.remote;
+package org.sufficientlysecure.keychain.remote;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Id;
-public class AppSettings {
- private String packageName;
- private byte[] packageSignature;
- private long keyId = Id.key.none;
- private int encryptionAlgorithm;
- private int hashAlgorithm;
- private int compression;
+public class AccountSettings {
+ private String mAccountName;
+ private long mKeyId = Id.key.none;
+ private int mEncryptionAlgorithm;
+ private int mHashAlgorithm;
+ private int mCompression;
- public AppSettings() {
+ public AccountSettings() {
}
- public AppSettings(String packageName, byte[] packageSignature) {
+ public AccountSettings(String accountName) {
super();
- this.packageName = packageName;
- this.packageSignature = packageSignature;
- // defaults:
- this.encryptionAlgorithm = PGPEncryptedData.AES_256;
- this.hashAlgorithm = HashAlgorithmTags.SHA512;
- this.compression = Id.choice.compression.zlib;
- }
+ this.mAccountName = accountName;
- public String getPackageName() {
- return packageName;
- }
-
- public void setPackageName(String packageName) {
- this.packageName = packageName;
+ // defaults:
+ this.mEncryptionAlgorithm = PGPEncryptedData.AES_256;
+ this.mHashAlgorithm = HashAlgorithmTags.SHA512;
+ this.mCompression = Id.choice.compression.zlib;
}
- public byte[] getPackageSignature() {
- return packageSignature;
+ public String getAccountName() {
+ return mAccountName;
}
- public void setPackageSignature(byte[] packageSignature) {
- this.packageSignature = packageSignature;
+ public void setAccountName(String mAccountName) {
+ this.mAccountName = mAccountName;
}
public long getKeyId() {
- return keyId;
+ return mKeyId;
}
public void setKeyId(long scretKeyId) {
- this.keyId = scretKeyId;
+ this.mKeyId = scretKeyId;
}
public int getEncryptionAlgorithm() {
- return encryptionAlgorithm;
+ return mEncryptionAlgorithm;
}
public void setEncryptionAlgorithm(int encryptionAlgorithm) {
- this.encryptionAlgorithm = encryptionAlgorithm;
+ this.mEncryptionAlgorithm = encryptionAlgorithm;
}
public int getHashAlgorithm() {
- return hashAlgorithm;
+ return mHashAlgorithm;
}
public void setHashAlgorithm(int hashAlgorithm) {
- this.hashAlgorithm = hashAlgorithm;
+ this.mHashAlgorithm = hashAlgorithm;
}
public int getCompression() {
- return compression;
+ return mCompression;
}
public void setCompression(int compression) {
- this.compression = compression;
+ this.mCompression = compression;
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java
new file mode 100644
index 000000000..6c7e51bf0
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 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.remote;
+
+import org.spongycastle.bcpg.HashAlgorithmTags;
+import org.spongycastle.openpgp.PGPEncryptedData;
+import org.sufficientlysecure.keychain.Id;
+
+public class AppSettings {
+ private String mPackageName;
+ private byte[] mPackageSignature;
+
+ public AppSettings() {
+
+ }
+
+ public AppSettings(String packageName, byte[] packageSignature) {
+ super();
+ this.mPackageName = packageName;
+ this.mPackageSignature = packageSignature;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public void setPackageName(String packageName) {
+ this.mPackageName = packageName;
+ }
+
+ public byte[] getPackageSignature() {
+ return mPackageSignature;
+ }
+
+ public void setPackageSignature(byte[] packageSignature) {
+ this.mPackageSignature = packageSignature;
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index f697faa6e..ad0c658ad 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.service.remote;
+package org.sufficientlysecure.keychain.remote;
import android.app.PendingIntent;
import android.content.Intent;
@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -47,10 +48,6 @@ import java.util.ArrayList;
public class OpenPgpService extends RemoteService {
- private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551;
- private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552;
- private static final int PRIVATE_REQUEST_CODE_GET_KEYS = 553;
-
/**
* Search database for key ids based on emails.
*
@@ -100,7 +97,9 @@ public class OpenPgpService extends RemoteService {
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
// return PendingIntent to be executed by client
Intent result = new Intent();
@@ -126,7 +125,9 @@ public class OpenPgpService extends RemoteService {
intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
// return PendingIntent to be executed by client
Intent result = new Intent();
@@ -136,7 +137,7 @@ public class OpenPgpService extends RemoteService {
}
private Intent signImpl(Intent data, ParcelFileDescriptor input,
- ParcelFileDescriptor output, AppSettings appSettings) {
+ ParcelFileDescriptor output, AccountSettings accSettings) {
try {
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
@@ -145,11 +146,11 @@ public class OpenPgpService extends RemoteService {
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
} else {
- passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
+ passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), accSettings.getKeyId());
}
if (passphrase == null) {
// get PendingIntent for passphrase input, add it to given params and return to client
- Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
+ Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId());
return passphraseBundle;
}
@@ -163,9 +164,9 @@ public class OpenPgpService extends RemoteService {
// sign-only
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os);
builder.enableAsciiArmorOutput(asciiArmor)
- .signatureHashAlgorithm(appSettings.getHashAlgorithm())
+ .signatureHashAlgorithm(accSettings.getHashAlgorithm())
.signatureForceV3(false)
- .signatureKeyId(appSettings.getKeyId())
+ .signatureKeyId(accSettings.getKeyId())
.signaturePassphrase(passphrase);
builder.build().execute();
} finally {
@@ -186,7 +187,7 @@ public class OpenPgpService extends RemoteService {
}
private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
- ParcelFileDescriptor output, AppSettings appSettings, boolean sign) {
+ ParcelFileDescriptor output, AccountSettings accSettings, boolean sign) {
try {
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
@@ -208,14 +209,15 @@ public class OpenPgpService extends RemoteService {
} else {
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_ERROR,
- new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!"));
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR,
+ "Missing parameter user_ids or key_ids!"));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
}
// add own key for encryption
keyIds = Arrays.copyOf(keyIds, keyIds.length + 1);
- keyIds[keyIds.length - 1] = appSettings.getKeyId();
+ keyIds[keyIds.length - 1] = accSettings.getKeyId();
// build InputData and write into OutputStream
// Get Input- and OutputStream from ParcelFileDescriptor
@@ -227,8 +229,8 @@ public class OpenPgpService extends RemoteService {
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os);
builder.enableAsciiArmorOutput(asciiArmor)
- .compressionId(appSettings.getCompression())
- .symmetricEncryptionAlgorithm(appSettings.getEncryptionAlgorithm())
+ .compressionId(accSettings.getCompression())
+ .symmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
.encryptionKeyIds(keyIds);
if (sign) {
@@ -237,18 +239,18 @@ public class OpenPgpService extends RemoteService {
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
} else {
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
- appSettings.getKeyId());
+ accSettings.getKeyId());
}
if (passphrase == null) {
// get PendingIntent for passphrase input, add it to given params and return to client
- Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
+ Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId());
return passphraseBundle;
}
// sign and encrypt
- builder.signatureHashAlgorithm(appSettings.getHashAlgorithm())
+ builder.signatureHashAlgorithm(accSettings.getHashAlgorithm())
.signatureForceV3(false)
- .signatureKeyId(appSettings.getKeyId())
+ .signatureKeyId(accSettings.getKeyId())
.signaturePassphrase(passphrase);
} else {
// encrypt only
@@ -274,7 +276,7 @@ public class OpenPgpService extends RemoteService {
}
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
- ParcelFileDescriptor output, AppSettings appSettings) {
+ ParcelFileDescriptor output, AccountSettings accSettings) {
try {
// Get Input- and OutputStream from ParcelFileDescriptor
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
@@ -289,7 +291,8 @@ public class OpenPgpService extends RemoteService {
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
builder.assumeSymmetric(false) // no support for symmetric encryption
- .enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption
+ // allow only the private key for this app for decryption
+ .enforcedKeyId(accSettings.getKeyId())
.passphrase(passphrase);
// TODO: currently does not support binary signed-only content
@@ -297,7 +300,7 @@ public class OpenPgpService extends RemoteService {
if (decryptVerifyResult.isKeyPassphraseNeeded()) {
// get PendingIntent for passphrase input, add it to given params and return to client
- Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
+ Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId());
return passphraseBundle;
} else if (decryptVerifyResult.isSymmetricPassphraseNeeded()) {
throw new PgpGeneralException("Decryption of symmetric content not supported by API!");
@@ -314,8 +317,9 @@ public class OpenPgpService extends RemoteService {
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo");
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(),
- PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
}
@@ -354,8 +358,9 @@ public class OpenPgpService extends RemoteService {
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo");
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(),
- PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
@@ -403,7 +408,8 @@ public class OpenPgpService extends RemoteService {
// version code is required and needs to correspond to version code of service!
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) {
Intent result = new Intent();
- OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
+ OpenPgpError error = new OpenPgpError
+ (OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
@@ -428,17 +434,26 @@ public class OpenPgpService extends RemoteService {
return errorResult;
}
- final AppSettings appSettings = getAppSettings();
+ String accName;
+ if (data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME) != null) {
+ accName = data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME);
+ } else {
+ accName = "default";
+ }
+ final AccountSettings accSettings = getAccSettings(accName);
+ if (accSettings == null) {
+ return getCreateAccountIntent(data, accName);
+ }
String action = data.getAction();
if (OpenPgpApi.ACTION_SIGN.equals(action)) {
- return signImpl(data, input, output, appSettings);
+ return signImpl(data, input, output, accSettings);
} else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
- return encryptAndSignImpl(data, input, output, appSettings, false);
+ return encryptAndSignImpl(data, input, output, accSettings, false);
} else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
- return encryptAndSignImpl(data, input, output, appSettings, true);
+ return encryptAndSignImpl(data, input, output, accSettings, true);
} else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
- return decryptAndVerifyImpl(data, input, output, appSettings);
+ return decryptAndVerifyImpl(data, input, output, accSettings);
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
return getKeyImpl(data);
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java
index cb556be39..8cea3cd21 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java
@@ -15,18 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.service.remote;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.openintents.openpgp.OpenPgpError;
-import org.openintents.openpgp.util.OpenPgpApi;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.util.Log;
+package org.sufficientlysecure.keychain.remote;
import android.app.PendingIntent;
import android.app.Service;
@@ -39,16 +28,24 @@ import android.content.pm.Signature;
import android.net.Uri;
import android.os.Binder;
+import org.openintents.openpgp.OpenPgpError;
+import org.openintents.openpgp.util.OpenPgpApi;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
/**
* Abstract service class for remote APIs that handle app registration and user input.
*/
public abstract class RemoteService extends Service {
Context mContext;
- private static final int PRIVATE_REQUEST_CODE_REGISTER = 651;
- private static final int PRIVATE_REQUEST_CODE_ERROR = 652;
-
-
public Context getContext() {
return mContext;
}
@@ -56,13 +53,10 @@ public abstract class RemoteService extends Service {
protected Intent isAllowed(Intent data) {
try {
if (isCallerAllowed(false)) {
-
return null;
} else {
- String[] callingPackages = getPackageManager().getPackagesForUid(
- Binder.getCallingUid());
- // TODO: currently simply uses first entry
- String packageName = callingPackages[0];
+ String packageName = getCurrentCallingPackage();
+ Log.d(Constants.TAG, "isAllowed packageName: " + packageName);
byte[] packageSignature;
try {
@@ -84,7 +78,9 @@ public abstract class RemoteService extends Service {
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
// return PendingIntent to be executed by client
Intent result = new Intent();
@@ -98,10 +94,13 @@ public abstract class RemoteService extends Service {
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
- intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature));
+ intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE,
+ getString(R.string.api_error_wrong_signature));
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
- PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
// return PendingIntent to be executed by client
Intent result = new Intent();
@@ -123,26 +122,57 @@ public abstract class RemoteService extends Service {
}
/**
- * Retrieves AppSettings from database for the application calling this remote service
+ * Returns package name associated with the UID, which is assigned to the process that sent you the
+ * current transaction that is being processed :)
*
- * @return
+ * @return package name
*/
- protected AppSettings getAppSettings() {
+ private String getCurrentCallingPackage() {
+ // TODO:
+ // callingPackages contains more than one entry when sharedUserId has been used...
String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
+ String currentPkg = callingPackages[0];
+ Log.d(Constants.TAG, "currentPkg: " + currentPkg);
- // get app settings for this package
- for (int i = 0; i < callingPackages.length; i++) {
- String currentPkg = callingPackages[i];
+ return currentPkg;
+ }
+
+ /**
+ * Retrieves AccountSettings from database for the application calling this remote service
+ *
+ * @return
+ */
+ protected AccountSettings getAccSettings(String accountName) {
+ String currentPkg = getCurrentCallingPackage();
+ Log.d(Constants.TAG, "accountName: " + accountName);
- Uri uri = KeychainContract.ApiApps.buildByPackageNameUri(currentPkg);
+ Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(currentPkg, accountName);
- AppSettings settings = ProviderHelper.getApiAppSettings(this, uri);
+ AccountSettings settings = ProviderHelper.getApiAccountSettings(this, uri);
- if (settings != null)
- return settings;
- }
+ return settings; // can be null!
+ }
+
+ protected Intent getCreateAccountIntent(Intent data, String accountName) {
+ String packageName = getCurrentCallingPackage();
+ Log.d(Constants.TAG, "accountName: " + accountName);
+
+ Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
+ intent.setAction(RemoteServiceActivity.ACTION_CREATE_ACCOUNT);
+ intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(RemoteServiceActivity.EXTRA_ACC_NAME, accountName);
+ intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
+
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
+ intent,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+
+ // return PendingIntent to be executed by client
+ Intent result = new Intent();
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
- return null;
+ return result;
}
/**
@@ -177,7 +207,7 @@ public abstract class RemoteService extends Service {
}
}
- Log.d(Constants.TAG, "Caller is NOT allowed!");
+ Log.d(Constants.TAG, "Uid is NOT allowed!");
return false;
}
@@ -189,7 +219,7 @@ public abstract class RemoteService extends Service {
* @throws WrongPackageSignatureException
*/
private boolean isPackageAllowed(String packageName) throws WrongPackageSignatureException {
- Log.d(Constants.TAG, "packageName: " + packageName);
+ Log.d(Constants.TAG, "isPackageAllowed packageName: " + packageName);
ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(this);
Log.d(Constants.TAG, "allowed: " + allowedPkgs);
@@ -217,6 +247,7 @@ public abstract class RemoteService extends Service {
}
}
+ Log.d(Constants.TAG, "Package is NOT allowed! packageName: " + packageName);
return false;
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/WrongPackageSignatureException.java
new file mode 100644
index 000000000..6f44a65e9
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/WrongPackageSignatureException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 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.remote;
+
+public class WrongPackageSignatureException extends Exception {
+
+ private static final long serialVersionUID = -8294642703122196028L;
+
+ public WrongPackageSignatureException(String message) {
+ super(message);
+ }
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java
index a7afc9698..671a3e0aa 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java
@@ -15,13 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.service.remote;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ActionBarHelper;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.util.Log;
+package org.sufficientlysecure.keychain.remote.ui;
import android.content.Intent;
import android.net.Uri;
@@ -31,17 +25,25 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-public class AppSettingsActivity extends ActionBarActivity {
- private Uri mAppUri;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ActionBarHelper;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.remote.AccountSettings;
+import org.sufficientlysecure.keychain.util.Log;
+
+public class AccountSettingsActivity extends ActionBarActivity {
+ private Uri mAccountUri;
- private AppSettingsFragment mSettingsFragment;
+ private AccountSettingsFragment mAccountSettingsFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate a "Done" custom action bar
- ActionBarHelper.setDoneView(getSupportActionBar(), R.string.api_settings_save,
+ ActionBarHelper.setOneButtonView(getSupportActionBar(),
+ R.string.api_settings_save, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -50,57 +52,58 @@ public class AppSettingsActivity extends ActionBarActivity {
}
});
- setContentView(R.layout.api_app_settings_activity);
+ setContentView(R.layout.api_account_settings_activity);
- mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
- R.id.api_app_settings_fragment);
+ mAccountSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById(
+ R.id.api_account_settings_fragment);
Intent intent = getIntent();
- mAppUri = intent.getData();
- if (mAppUri == null) {
+ mAccountUri = intent.getData();
+ if (mAccountUri == null) {
Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!");
finish();
return;
} else {
- Log.d(Constants.TAG, "uri: " + mAppUri);
- loadData(mAppUri);
+ Log.d(Constants.TAG, "uri: " + mAccountUri);
+ loadData(savedInstanceState, mAccountUri);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.api_app_settings, menu);
+ getMenuInflater().inflate(R.menu.api_account_settings, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case R.id.menu_api_settings_revoke:
- revokeAccess();
- return true;
- case R.id.menu_api_settings_cancel:
- finish();
- return true;
+ case R.id.menu_account_settings_delete:
+ deleteAccount();
+ return true;
+ case R.id.menu_account_settings_cancel:
+ finish();
+ return true;
}
return super.onOptionsItemSelected(item);
}
- private void loadData(Uri appUri) {
- AppSettings settings = ProviderHelper.getApiAppSettings(this, appUri);
- mSettingsFragment.setAppSettings(settings);
+ private void loadData(Bundle savedInstanceState, Uri accountUri) {
+ // TODO: load this also like other fragment with newInstance arguments?
+ AccountSettings settings = ProviderHelper.getApiAccountSettings(this, accountUri);
+ mAccountSettingsFragment.setAccSettings(settings);
}
- private void revokeAccess() {
- if (getContentResolver().delete(mAppUri, null, null) <= 0) {
+ private void deleteAccount() {
+ if (getContentResolver().delete(mAccountUri, null, null) <= 0) {
throw new RuntimeException();
}
finish();
}
private void save() {
- ProviderHelper.updateApiApp(this, mSettingsFragment.getAppSettings(), mAppUri);
+ ProviderHelper.updateApiAccount(this, mAccountSettingsFragment.getAccSettings(), mAccountUri);
finish();
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
new file mode 100644
index 000000000..0931e6e31
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
@@ -0,0 +1,176 @@
+/*
+ * 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.remote.ui;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.beardedhen.androidbootstrap.BootstrapButton;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.remote.AccountSettings;
+import org.sufficientlysecure.keychain.ui.EditKeyActivity;
+import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
+import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
+import org.sufficientlysecure.keychain.util.AlgorithmNames;
+
+public class AccountSettingsFragment extends Fragment implements
+ SelectSecretKeyLayoutFragment.SelectSecretKeyCallback {
+
+ // model
+ private AccountSettings mAccSettings;
+
+ // view
+ private TextView mAccNameView;
+ private Spinner mEncryptionAlgorithm;
+ private Spinner mHashAlgorithm;
+ private Spinner mCompression;
+
+ private SelectSecretKeyLayoutFragment mSelectKeyFragment;
+ private BootstrapButton mCreateKeyButton;
+
+ KeyValueSpinnerAdapter mEncryptionAdapter;
+ KeyValueSpinnerAdapter mHashAdapter;
+ KeyValueSpinnerAdapter mCompressionAdapter;
+
+ public AccountSettings getAccSettings() {
+ return mAccSettings;
+ }
+
+ public void setAccSettings(AccountSettings accountSettings) {
+ this.mAccSettings = accountSettings;
+
+ mAccNameView.setText(accountSettings.getAccountName());
+ mSelectKeyFragment.selectKey(accountSettings.getKeyId());
+ mEncryptionAlgorithm.setSelection(mEncryptionAdapter.getPosition(accountSettings
+ .getEncryptionAlgorithm()));
+ mHashAlgorithm.setSelection(mHashAdapter.getPosition(accountSettings.getHashAlgorithm()));
+ mCompression.setSelection(mCompressionAdapter.getPosition(accountSettings.getCompression()));
+ }
+
+ /**
+ * Inflate the layout for this fragment
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.api_account_settings_fragment, container, false);
+ initView(view);
+ return view;
+ }
+
+ /**
+ * Set error String on key selection
+ *
+ * @param error
+ */
+ public void setErrorOnSelectKeyFragment(String error) {
+ mSelectKeyFragment.setError(error);
+ }
+
+ private void initView(View view) {
+ mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getFragmentManager().findFragmentById(
+ R.id.api_account_settings_select_key_fragment);
+ mSelectKeyFragment.setCallback(this);
+
+ mAccNameView = (TextView) view.findViewById(R.id.api_account_settings_acc_name);
+ mEncryptionAlgorithm = (Spinner) view
+ .findViewById(R.id.api_account_settings_encryption_algorithm);
+ mHashAlgorithm = (Spinner) view.findViewById(R.id.api_account_settings_hash_algorithm);
+ mCompression = (Spinner) view.findViewById(R.id.api_account_settings_compression);
+ mCreateKeyButton = (BootstrapButton) view.findViewById(R.id.api_account_settings_create_key);
+
+ mCreateKeyButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ createKey();
+ }
+ });
+
+ AlgorithmNames algorithmNames = new AlgorithmNames(getActivity());
+
+ mEncryptionAdapter = new KeyValueSpinnerAdapter(getActivity(),
+ algorithmNames.getEncryptionNames());
+ mEncryptionAlgorithm.setAdapter(mEncryptionAdapter);
+ mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ mAccSettings.setEncryptionAlgorithm((int) id);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ mHashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames());
+ mHashAlgorithm.setAdapter(mHashAdapter);
+ mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ mAccSettings.setHashAlgorithm((int) id);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ mCompressionAdapter = new KeyValueSpinnerAdapter(getActivity(),
+ algorithmNames.getCompressionNames());
+ mCompression.setAdapter(mCompressionAdapter);
+ mCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ mAccSettings.setCompression((int) id);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+ }
+
+ private void createKey() {
+ Intent intent = new Intent(getActivity(), EditKeyActivity.class);
+ intent.setAction(EditKeyActivity.ACTION_CREATE_KEY);
+ intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true);
+ // set default user id to account name TODO: not working currently in EditKey
+ intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, mAccSettings.getAccountName());
+ startActivityForResult(intent, 0);
+ }
+
+ /**
+ * callback from select secret key fragment
+ */
+ @Override
+ public void onKeySelected(long secretKeyId) {
+ mAccSettings.setKeyId(secretKeyId);
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java
new file mode 100644
index 000000000..8e65a2f04
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java
@@ -0,0 +1,200 @@
+/*
+ * 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.remote.ui;
+
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.support.v4.widget.CursorAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.ui.widget.FixedListView;
+import org.sufficientlysecure.keychain.util.Log;
+
+public class AccountsListFragment extends ListFragment implements
+ LoaderManager.LoaderCallbacks<Cursor> {
+
+ private static final String ARG_DATA_URI = "uri";
+
+ // This is the Adapter being used to display the list's data.
+ AccountsAdapter mAdapter;
+
+ private Uri mDataUri;
+
+ /**
+ * Creates new instance of this fragment
+ */
+ public static AccountsListFragment newInstance(Uri dataUri) {
+ AccountsListFragment frag = new AccountsListFragment();
+
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_DATA_URI, dataUri);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View layout = super.onCreateView(inflater, container,
+ savedInstanceState);
+ ListView lv = (ListView) layout.findViewById(android.R.id.list);
+ ViewGroup parent = (ViewGroup) lv.getParent();
+
+ /*
+ * http://stackoverflow.com/a/15880684
+ * Remove ListView and add FixedListView in its place.
+ * This is done here programatically to be still able to use the progressBar of ListFragment.
+ *
+ * We want FixedListView to be able to put this ListFragment inside a ScrollView
+ */
+ int lvIndex = parent.indexOfChild(lv);
+ parent.removeViewAt(lvIndex);
+ FixedListView newLv = new FixedListView(getActivity());
+ newLv.setId(android.R.id.list);
+ parent.addView(newLv, lvIndex, lv.getLayoutParams());
+ return layout;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ mDataUri = getArguments().getParcelable(ARG_DATA_URI);
+
+ getListView().setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
+ String selectedAccountName = mAdapter.getItemAccountName(position);
+ Uri accountUri = mDataUri.buildUpon().appendEncodedPath(selectedAccountName).build();
+ Log.d(Constants.TAG, "accountUri: " + accountUri);
+
+ // edit account settings
+ Intent intent = new Intent(getActivity(), AccountSettingsActivity.class);
+ intent.setData(accountUri);
+ startActivity(intent);
+ }
+ });
+
+ // Give some text to display if there is no data. In a real
+ // application this would come from a resource.
+ setEmptyText(getString(R.string.api_settings_accounts_empty));
+
+ // We have a menu item to show in action bar.
+ setHasOptionsMenu(true);
+
+ // Create an empty adapter we will use to display the loaded data.
+ mAdapter = new AccountsAdapter(getActivity(), null, 0);
+ setListAdapter(mAdapter);
+
+ // Prepare the loader. Either re-connect with an existing one,
+ // or start a new one.
+ getLoaderManager().initLoader(0, null, this);
+ }
+
+ // These are the Contacts rows that we will retrieve.
+ static final String[] PROJECTION = new String[]{
+ KeychainContract.ApiAccounts._ID, // 0
+ KeychainContract.ApiAccounts.ACCOUNT_NAME // 1
+ };
+
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ // This is called when a new Loader needs to be created. This
+ // sample only has one Loader, so we don't care about the ID.
+
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getActivity(), mDataUri, PROJECTION, null, null,
+ KeychainContract.ApiAccounts.ACCOUNT_NAME + " COLLATE LOCALIZED ASC");
+ }
+
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ // Swap the new cursor in. (The framework will take care of closing the
+ // old cursor once we return.)
+ mAdapter.swapCursor(data);
+ }
+
+ public void onLoaderReset(Loader<Cursor> loader) {
+ // This is called when the last Cursor provided to onLoadFinished()
+ // above is about to be closed. We need to make sure we are no
+ // longer using it.
+ mAdapter.swapCursor(null);
+ }
+
+ private class AccountsAdapter extends CursorAdapter {
+ private LayoutInflater mInflater;
+
+ public AccountsAdapter(Context context, Cursor c, int flags) {
+ super(context, c, flags);
+
+ mInflater = LayoutInflater.from(context);
+ }
+
+ /**
+ * Similar to CursorAdapter.getItemId().
+ * Required to build Uris for api app view, which is not based on row ids
+ *
+ * @param position
+ * @return
+ */
+ public String getItemAccountName(int position) {
+ if (mDataValid && mCursor != null) {
+ if (mCursor.moveToPosition(position)) {
+ return mCursor.getString(1);
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ TextView text = (TextView) view.findViewById(R.id.api_accounts_adapter_item_name);
+
+ String accountName = cursor.getString(1);
+ text.setText(accountName);
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ return mInflater.inflate(R.layout.api_accounts_adapter_list_item, null);
+ }
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java
new file mode 100644
index 000000000..9e0ba49eb
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 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.remote.ui;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.remote.AppSettings;
+import org.sufficientlysecure.keychain.util.Log;
+
+public class AppSettingsActivity extends ActionBarActivity {
+ private Uri mAppUri;
+
+ private AppSettingsFragment mSettingsFragment;
+ private AccountsListFragment mAccountsListFragment;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // let the actionbar look like Android's contact app
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setIcon(android.R.color.transparent);
+ actionBar.setHomeButtonEnabled(true);
+
+ setContentView(R.layout.api_app_settings_activity);
+
+ mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
+ R.id.api_app_settings_fragment);
+
+ Intent intent = getIntent();
+ mAppUri = intent.getData();
+ if (mAppUri == null) {
+ Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!");
+ finish();
+ return;
+ } else {
+ Log.d(Constants.TAG, "uri: " + mAppUri);
+ loadData(savedInstanceState, mAppUri);
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.api_app_settings, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_api_settings_revoke:
+ revokeAccess();
+ return true;
+ case R.id.menu_api_settings_cancel:
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void loadData(Bundle savedInstanceState, Uri appUri) {
+ // TODO: load this also like other fragment with newInstance arguments?
+ AppSettings settings = ProviderHelper.getApiAppSettings(this, appUri);
+ mSettingsFragment.setAppSettings(settings);
+
+ String appName;
+ PackageManager pm = getPackageManager();
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(settings.getPackageName(), 0);
+ appName = (String) pm.getApplicationLabel(ai);
+ } catch (PackageManager.NameNotFoundException e) {
+ // fallback
+ appName = settings.getPackageName();
+ }
+ setTitle(appName);
+
+ Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build();
+ Log.d(Constants.TAG, "accountsUri: " + accountsUri);
+ startListFragment(savedInstanceState, accountsUri);
+ }
+
+ private void startListFragment(Bundle savedInstanceState, Uri dataUri) {
+ // However, if we're being restored from a previous state,
+ // then we don't need to do anything and should return or else
+ // we could end up with overlapping fragments.
+ if (savedInstanceState != null) {
+ return;
+ }
+
+ // Create an instance of the fragment
+ mAccountsListFragment = AccountsListFragment.newInstance(dataUri);
+
+ // Add the fragment to the 'fragment_container' FrameLayout
+ // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.api_accounts_list_fragment, mAccountsListFragment)
+ .commitAllowingStateLoss();
+ // do it immediately!
+ getSupportFragmentManager().executePendingTransactions();
+ }
+
+ private void revokeAccess() {
+ if (getContentResolver().delete(mAppUri, null, null) <= 0) {
+ throw new RuntimeException();
+ }
+ finish();
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java
new file mode 100644
index 000000000..a6db02708
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java
@@ -0,0 +1,108 @@
+/*
+ * 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.remote.ui;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.spongycastle.util.encoders.Hex;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.remote.AppSettings;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class AppSettingsFragment extends Fragment {
+
+ // model
+ private AppSettings mAppSettings;
+
+ // view
+ private TextView mAppNameView;
+ private ImageView mAppIconView;
+ private TextView mPackageName;
+ private TextView mPackageSignature;
+
+ public AppSettings getAppSettings() {
+ return mAppSettings;
+ }
+
+ public void setAppSettings(AppSettings appSettings) {
+ this.mAppSettings = appSettings;
+ updateView(appSettings);
+ }
+
+ /**
+ * Inflate the layout for this fragment
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.api_app_settings_fragment, container, false);
+ 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);
+ return view;
+ }
+
+ private void updateView(AppSettings appSettings) {
+ // get application name and icon from package manager
+ String appName;
+ Drawable appIcon = null;
+ PackageManager pm = getActivity().getApplicationContext().getPackageManager();
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(appSettings.getPackageName(), 0);
+
+ appName = (String) pm.getApplicationLabel(ai);
+ appIcon = pm.getApplicationIcon(ai);
+ } catch (NameNotFoundException e) {
+ // fallback
+ appName = appSettings.getPackageName();
+ }
+ mAppNameView.setText(appName);
+ mAppIconView.setImageDrawable(appIcon);
+
+ // advanced info: package name
+ mPackageName.setText(appSettings.getPackageName());
+
+ // advanced info: package signature SHA-256
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(appSettings.getPackageSignature());
+ byte[] digest = md.digest();
+ String signature = new String(Hex.encode(digest));
+
+ mPackageSignature.setText(signature);
+ } catch (NoSuchAlgorithmException e) {
+ Log.e(Constants.TAG, "Should not happen!", e);
+ }
+ }
+
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java
index 3c553fff5..f86d279f0 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java
@@ -15,14 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.service.remote;
+package org.sufficientlysecure.keychain.remote.ui;
+import android.os.Bundle;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.DrawerActivity;
-import android.os.Bundle;
-
-public class RegisteredAppsListActivity extends DrawerActivity {
+public class AppsListActivity extends DrawerActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java
index fed267a44..f3fa6e7c6 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java
@@ -15,14 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.service.remote;
+package org.sufficientlysecure.keychain.remote.ui;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
-
-import android.content.ContentUris;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -30,11 +28,22 @@ import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
+import android.support.v4.widget.CursorAdapter;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
+import org.sufficientlysecure.keychain.util.Log;
-public class RegisteredAppsListFragment extends ListFragment implements
+public class AppsListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
// This is the Adapter being used to display the list's data.
@@ -47,9 +56,10 @@ public class RegisteredAppsListFragment extends ListFragment implements
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
+ String selectedPackageName = mAdapter.getItemPackageName(position);
// edit app settings
Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
- intent.setData(ContentUris.withAppendedId(KeychainContract.ApiApps.CONTENT_URI, id));
+ intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName));
startActivity(intent);
}
});
@@ -71,7 +81,10 @@ public class RegisteredAppsListFragment extends ListFragment implements
}
// These are the Contacts rows that we will retrieve.
- static final String[] PROJECTION = new String[] { ApiApps._ID, ApiApps.PACKAGE_NAME };
+ static final String[] PROJECTION = new String[]{
+ ApiApps._ID, // 0
+ ApiApps.PACKAGE_NAME // 1
+ };
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
@@ -99,4 +112,65 @@ public class RegisteredAppsListFragment extends ListFragment implements
mAdapter.swapCursor(null);
}
-} \ No newline at end of file
+ private class RegisteredAppsAdapter extends CursorAdapter {
+
+ private LayoutInflater mInflater;
+ private PackageManager mPM;
+
+ public RegisteredAppsAdapter(Context context, Cursor c, int flags) {
+ super(context, c, flags);
+
+ mInflater = LayoutInflater.from(context);
+ mPM = context.getApplicationContext().getPackageManager();
+ }
+
+ /**
+ * Similar to CursorAdapter.getItemId().
+ * Required to build Uris for api app view, which is not based on row ids
+ *
+ * @param position
+ * @return
+ */
+ public String getItemPackageName(int position) {
+ if (mDataValid && mCursor != null) {
+ if (mCursor.moveToPosition(position)) {
+ return mCursor.getString(1);
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name);
+ ImageView icon = (ImageView) view.findViewById(R.id.api_apps_adapter_item_icon);
+
+ String packageName = cursor.getString(cursor.getColumnIndex(ApiApps.PACKAGE_NAME));
+ if (packageName != null) {
+ // get application name
+ try {
+ ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0);
+
+ text.setText(mPM.getApplicationLabel(ai));
+ icon.setImageDrawable(mPM.getApplicationIcon(ai));
+ } catch (final PackageManager.NameNotFoundException e) {
+ // fallback
+ text.setText(packageName);
+ }
+ } else {
+ // fallback
+ text.setText(packageName);
+ }
+
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ return mInflater.inflate(R.layout.api_apps_adapter_list_item, null);
+ }
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
index 11b3ee217..a894da448 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java
@@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.service.remote;
+package org.sufficientlysecure.keychain.remote.ui;
import android.content.Intent;
import android.os.Bundle;
@@ -32,7 +32,10 @@ import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.remote.AccountSettings;
+import org.sufficientlysecure.keychain.remote.AppSettings;
import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
@@ -42,6 +45,8 @@ import java.util.ArrayList;
public class RemoteServiceActivity extends ActionBarActivity {
public static final String ACTION_REGISTER = Constants.INTENT_PREFIX + "API_ACTIVITY_REGISTER";
+ public static final String ACTION_CREATE_ACCOUNT = Constants.INTENT_PREFIX
+ + "API_ACTIVITY_CREATE_ACCOUNT";
public static final String ACTION_CACHE_PASSPHRASE = Constants.INTENT_PREFIX
+ "API_ACTIVITY_CACHE_PASSPHRASE";
public static final String ACTION_SELECT_PUB_KEYS = Constants.INTENT_PREFIX
@@ -58,6 +63,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
// register action
public static final String EXTRA_PACKAGE_NAME = "package_name";
public static final String EXTRA_PACKAGE_SIGNATURE = "package_signature";
+ // create acc action
+ 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";
@@ -66,7 +73,9 @@ public class RemoteServiceActivity extends ActionBarActivity {
public static final String EXTRA_ERROR_MESSAGE = "error_message";
// register view
- private AppSettingsFragment mSettingsFragment;
+ private AppSettingsFragment mAppSettingsFragment;
+ // create acc view
+ private AccountSettingsFragment mAccSettingsFragment;
// select pub keys view
private SelectPublicKeyFragment mSelectFragment;
@@ -86,21 +95,62 @@ public class RemoteServiceActivity extends ActionBarActivity {
if (ACTION_REGISTER.equals(action)) {
final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
+ Log.d(Constants.TAG, "ACTION_REGISTER packageName: "+packageName);
// Inflate a "Done"/"Cancel" custom action bar view
- ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow,
+ ActionBarHelper.setTwoButtonView(getSupportActionBar(),
+ R.string.api_register_allow, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
// Allow
+ ProviderHelper.insertApiApp(RemoteServiceActivity.this,
+ mAppSettingsFragment.getAppSettings());
+
+ // give data through for new service call
+ Intent resultData = extras.getParcelable(EXTRA_DATA);
+ RemoteServiceActivity.this.setResult(RESULT_OK, resultData);
+ RemoteServiceActivity.this.finish();
+ }
+ }, R.string.api_register_disallow, R.drawable.ic_action_cancel,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Disallow
+ RemoteServiceActivity.this.setResult(RESULT_CANCELED);
+ RemoteServiceActivity.this.finish();
+ }
+ }
+ );
+
+ setContentView(R.layout.api_remote_register_app);
+
+ mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
+ R.id.api_app_settings_fragment);
+
+ AppSettings settings = new AppSettings(packageName, packageSignature);
+ mAppSettingsFragment.setAppSettings(settings);
+ } else if (ACTION_CREATE_ACCOUNT.equals(action)) {
+ final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
+ final String accName = extras.getString(EXTRA_ACC_NAME);
+
+ // Inflate a "Done"/"Cancel" custom action bar view
+ ActionBarHelper.setTwoButtonView(getSupportActionBar(),
+ R.string.api_settings_save, R.drawable.ic_action_done,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Save
+
// user needs to select a key!
- if (mSettingsFragment.getAppSettings().getKeyId() == Id.key.none) {
- mSettingsFragment.setErrorOnSelectKeyFragment(
+ if (mAccSettingsFragment.getAccSettings().getKeyId() == Id.key.none) {
+ mAccSettingsFragment.setErrorOnSelectKeyFragment(
getString(R.string.api_register_error_select_key));
} else {
- ProviderHelper.insertApiApp(RemoteServiceActivity.this,
- mSettingsFragment.getAppSettings());
+ ProviderHelper.insertApiAccount(RemoteServiceActivity.this,
+ KeychainContract.ApiAccounts.buildBaseUri(packageName),
+ mAccSettingsFragment.getAccSettings());
// give data through for new service call
Intent resultData = extras.getParcelable(EXTRA_DATA);
@@ -108,23 +158,24 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.finish();
}
}
- }, R.string.api_register_disallow, new View.OnClickListener() {
+ }, R.string.api_settings_cancel, R.drawable.ic_action_cancel,
+ new View.OnClickListener() {
@Override
public void onClick(View v) {
- // Disallow
+ // Cancel
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
RemoteServiceActivity.this.finish();
}
}
);
- setContentView(R.layout.api_app_register_activity);
+ setContentView(R.layout.api_remote_create_account);
- mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
- R.id.api_app_settings_fragment);
+ mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById(
+ R.id.api_account_settings_fragment);
- AppSettings settings = new AppSettings(packageName, packageSignature);
- mSettingsFragment.setAppSettings(settings);
+ AccountSettings settings = new AccountSettings(accName);
+ mAccSettingsFragment.setAccSettings(settings);
} else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);
Intent resultData = extras.getParcelable(EXTRA_DATA);
@@ -161,7 +212,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
}
// Inflate a "Done"/"Cancel" custom action bar view
- ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay,
+ ActionBarHelper.setTwoButtonView(getSupportActionBar(),
+ R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -173,7 +225,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.setResult(RESULT_OK, resultData);
RemoteServiceActivity.this.finish();
}
- }, R.string.btn_do_not_save, new View.OnClickListener() {
+ }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel
@@ -183,7 +235,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
}
);
- setContentView(R.layout.api_app_select_pub_keys_activity);
+ setContentView(R.layout.api_remote_select_pub_keys);
// set text on view
HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text);
@@ -214,7 +266,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
String text = "<font color=\"red\">" + errorMessage + "</font>";
// Inflate a "Done" custom action bar view
- ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay,
+ ActionBarHelper.setOneButtonView(getSupportActionBar(),
+ R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
@@ -224,7 +277,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
}
});
- setContentView(R.layout.api_app_error_message);
+ setContentView(R.layout.api_remote_error_message);
// set text on view
HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index d796ccf31..846eb8cf9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -17,62 +17,41 @@
package org.sufficientlysecure.keychain.service;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.GregorianCalendar;
-import java.util.List;
+import android.app.IntentService;
+import android.content.Context;
+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 org.spongycastle.openpgp.PGPKeyRing;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.*;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
-import org.sufficientlysecure.keychain.pgp.PgpHelper;
-import org.sufficientlysecure.keychain.pgp.PgpImportExport;
-import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
-import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
+import org.sufficientlysecure.keychain.pgp.*;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.util.HkpKeyServer;
-import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
+import org.sufficientlysecure.keychain.util.*;
-import android.app.IntentService;
-import android.content.Context;
-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 java.io.*;
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.List;
/**
* This Service contains all important long lasting operations for APG. It receives Intents with
* data from the activities or other apps, queues these intents, executes them, and stops itself
* after doing them.
*/
-public class KeychainIntentService extends IntentService implements ProgressDialogUpdater {
+public class KeychainIntentService extends IntentService
+ implements ProgressDialogUpdater, KeychainServiceListener {
/* extras that can be given by intent */
public static final String EXTRA_MESSENGER = "messenger";
@@ -159,6 +138,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// sign key
public static final String CERTIFY_KEY_MASTER_KEY_ID = "sign_key_master_key_id";
public static final String CERTIFY_KEY_PUB_KEY_ID = "sign_key_pub_key_id";
+ public static final String CERTIFY_KEY_UIDS = "sign_key_uids";
/*
* possible data keys as result send over messenger
@@ -324,8 +304,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId)
- .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
- .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+ .signatureHashAlgorithm(
+ Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(
+ PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().generateSignature();
} else if (signOnly) {
@@ -333,21 +315,26 @@ public class KeychainIntentService extends IntentService implements ProgressDial
builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId)
- .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
- .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+ .signatureHashAlgorithm(
+ Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(
+ PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().execute();
} else {
Log.d(Constants.TAG, "encrypt...");
builder.enableAsciiArmorOutput(useAsciiArmor)
.compressionId(compressionId)
- .symmetricEncryptionAlgorithm(Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
+ .symmetricEncryptionAlgorithm(
+ Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.encryptionKeyIds(encryptionKeyIds)
.encryptionPassphrase(encryptionPassphrase)
.signatureKeyId(secretKeyId)
- .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
- .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+ .signatureHashAlgorithm(
+ Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(
+ PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().execute();
}
@@ -586,13 +573,24 @@ public class KeychainIntentService extends IntentService implements ProgressDial
String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE);
/* Operation */
+ int keysTotal = 2;
+ int keysCreated = 0;
+ setProgress(
+ getApplicationContext().getResources().
+ getQuantityString(R.plurals.progress_generating, keysTotal),
+ keysCreated,
+ keysTotal);
PgpKeyOperation keyOperations = new PgpKeyOperation(this, this);
PGPSecretKey masterKey = keyOperations.createKey(Id.choice.algorithm.rsa,
4096, passphrase, true);
+ keysCreated++;
+ setProgress(keysCreated, keysTotal);
PGPSecretKey subKey = keyOperations.createKey(Id.choice.algorithm.rsa,
4096, passphrase, false);
+ keysCreated++;
+ setProgress(keysCreated, keysTotal);
// TODO: default to one master for cert, one sub for encrypt and one sub
// for sign
@@ -652,14 +650,11 @@ public class KeychainIntentService extends IntentService implements ProgressDial
if (data.containsKey(EXPORT_KEY_TYPE)) {
keyType = data.getInt(EXPORT_KEY_TYPE);
}
-
+ long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
String outputFile = data.getString(EXPORT_FILENAME);
+ // If not exporting all keys get the masterKeyIds of the keys to export from the intent
boolean exportAll = data.getBoolean(EXPORT_ALL);
- long keyRingMasterKeyId = -1;
- if (!exportAll) {
- keyRingMasterKeyId = data.getLong(EXPORT_KEY_RING_MASTER_KEY_ID);
- }
/* Operation */
@@ -668,27 +663,42 @@ public class KeychainIntentService extends IntentService implements ProgressDial
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
}
- // OutputStream
- FileOutputStream outStream = new FileOutputStream(outputFile);
+ ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
+ ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>();
+ ArrayList<Long> allPublicMasterKeyIds = ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
+ ArrayList<Long> allSecretMasterKeyIds = ProviderHelper.getSecretKeyRingsMasterKeyIds(this);
- ArrayList<Long> keyRingMasterKeyIds = new ArrayList<Long>();
if (exportAll) {
- // get all key ring row ids based on export type
-
- if (keyType == Id.type.public_key) {
- keyRingMasterKeyIds = ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
- } else {
- keyRingMasterKeyIds = ProviderHelper.getSecretKeyRingsMasterKeyIds(this);
+ // get all public key ring MasterKey ids
+ if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) {
+ publicMasterKeyIds = allPublicMasterKeyIds;
+ }
+ // get all secret key ring MasterKey ids
+ if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) {
+ secretMasterKeyIds = allSecretMasterKeyIds;
}
} else {
- keyRingMasterKeyIds.add(keyRingMasterKeyId);
+
+ for (long masterKeyId : masterKeyIds) {
+ if ((keyType == Id.type.public_key || keyType == Id.type.public_secret_key)
+ && allPublicMasterKeyIds.contains(masterKeyId)) {
+ publicMasterKeyIds.add(masterKeyId);
+ }
+ if ((keyType == Id.type.secret_key || keyType == Id.type.public_secret_key)
+ && allSecretMasterKeyIds.contains(masterKeyId)) {
+ secretMasterKeyIds.add(masterKeyId);
+ }
+ }
}
- Bundle resultData = new Bundle();
+ PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
+ Bundle resultData = pgpImportExport
+ .exportKeyRings(publicMasterKeyIds, secretMasterKeyIds,
+ new FileOutputStream(outputFile));
- PgpImportExport pgpImportExport = new PgpImportExport(this, this);
- resultData = pgpImportExport
- .exportKeyRings(keyRingMasterKeyIds, keyType, outStream);
+ if (mIsCanceled) {
+ boolean isDeleted = new File(outputFile).delete();
+ }
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
@@ -724,48 +734,58 @@ public class KeychainIntentService extends IntentService implements ProgressDial
ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST);
String keyServer = data.getString(DOWNLOAD_KEY_SERVER);
+ // TODO: add extra which requires fingerprint suport and force verification!
+ // only supported by newer sks keyserver versions
+
// this downloads the keys and places them into the ImportKeysListEntry entries
HkpKeyServer server = new HkpKeyServer(keyServer);
for (ImportKeysListEntry entry : entries) {
- byte[] downloadedKey = server.get(entry.getKeyId()).getBytes();
-
- /**
- * TODO: copied from ImportKeysListLoader
- *
- *
- * this parses the downloaded key
- */
- // need to have access to the bufferedInput, so we can reuse it for the possible
- // PGPObject chunks after the first one, e.g. files with several consecutive ASCII
- // armor blocks
- BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKey));
- try {
-
- // read all available blocks... (asc files can contain many blocks with BEGIN END)
- while (bufferedInput.available() > 0) {
- InputStream in = PGPUtil.getDecoderStream(bufferedInput);
- PGPObjectFactory objectFactory = new PGPObjectFactory(in);
-
- // go through all objects in this block
- Object obj;
- while ((obj = objectFactory.nextObject()) != null) {
- Log.d(Constants.TAG, "Found class: " + obj.getClass());
-
- if (obj instanceof PGPKeyRing) {
- PGPKeyRing newKeyring = (PGPKeyRing) obj;
-
- entry.setBytes(newKeyring.getEncoded());
- } else {
- Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!");
- }
+ // if available use complete fingerprint for get request
+ byte[] downloadedKeyBytes;
+ if (entry.getFingerPrintHex() != null) {
+ downloadedKeyBytes = server.get("0x" + entry.getFingerPrintHex()).getBytes();
+ } else {
+ downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes();
+ }
+
+ // create PGPKeyRing object based on downloaded armored key
+ PGPKeyRing downloadedKey = null;
+ BufferedInputStream bufferedInput =
+ new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes));
+ if (bufferedInput.available() > 0) {
+ InputStream in = PGPUtil.getDecoderStream(bufferedInput);
+ PGPObjectFactory objectFactory = new PGPObjectFactory(in);
+
+ // get first object in block
+ Object obj;
+ if ((obj = objectFactory.nextObject()) != null) {
+ Log.d(Constants.TAG, "Found class: " + obj.getClass());
+
+ if (obj instanceof PGPKeyRing) {
+ downloadedKey = (PGPKeyRing) obj;
+ } else {
+ throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
}
}
- } catch (Exception e) {
- Log.e(Constants.TAG, "Exception on parsing key file!", e);
}
+
+ // verify downloaded key by comparing fingerprints
+ if (entry.getFingerPrintHex() != null) {
+ String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex(downloadedKey.getPublicKey().getFingerprint());
+ if (downloadedKeyFp.equals(entry.getFingerPrintHex())) {
+ Log.d(Constants.TAG, "fingerprint of downloaded key is the same as the requested fingerprint!");
+ } else {
+ throw new PgpGeneralException("fingerprint of downloaded key is NOT the same as the requested fingerprint!");
+ }
+ }
+
+ // save key bytes in entry object for doing the
+ // actual import afterwards
+ entry.setBytes(downloadedKey.getEncoded());
}
+
Intent importIntent = new Intent(this, KeychainIntentService.class);
importIntent.setAction(ACTION_IMPORT_KEYRING);
Bundle importData = new Bundle();
@@ -786,6 +806,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
/* Input */
long masterKeyId = data.getLong(CERTIFY_KEY_MASTER_KEY_ID);
long pubKeyId = data.getLong(CERTIFY_KEY_PUB_KEY_ID);
+ ArrayList<String> userIds = data.getStringArrayList(CERTIFY_KEY_UIDS);
/* Operation */
String signaturePassPhrase = PassphraseCacheService.getCachedPassphrase(this,
@@ -793,7 +814,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
PgpKeyOperation keyOperation = new PgpKeyOperation(this, this);
PGPPublicKeyRing signedPubKeyRing = keyOperation.certifyKey(masterKeyId, pubKeyId,
- signaturePassPhrase);
+ userIds, signaturePassPhrase);
// store the signed key in our local cache
PgpImportExport pgpImportExport = new PgpImportExport(this, null);
@@ -811,10 +832,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
private void sendErrorToHandler(Exception e) {
// Service was canceled. Do not send error to handler.
- if (this.mIsCanceled)
+ if (this.mIsCanceled) {
return;
-
- Log.e(Constants.TAG, "ApgService Exception: ", e);
+ }
+ Log.e(Constants.TAG, "KeychainIntentService Exception: ", e);
e.printStackTrace();
Bundle data = new Bundle();
@@ -824,9 +845,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) {
// Service was canceled. Do not send message to handler.
- if (this.mIsCanceled)
+ if (this.mIsCanceled) {
return;
-
+ }
Message msg = Message.obtain();
msg.arg1 = arg1;
if (arg2 != null) {
@@ -877,4 +898,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public void setProgress(int progress, int max) {
setProgress(null, progress, max);
}
+
+ @Override
+ public boolean hasServiceStopped() {
+ return mIsCanceled;
+ }
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
index 6eba9cc83..92d012c80 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
@@ -17,11 +17,7 @@
package org.sufficientlysecure.keychain.service;
-import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
-import org.sufficientlysecure.keychain.R;
-
import android.app.Activity;
-import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.os.Bundle;
import android.os.Handler;
@@ -29,6 +25,8 @@ import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.widget.Toast;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
public class KeychainIntentServiceHandler extends Handler {
@@ -51,25 +49,31 @@ public class KeychainIntentServiceHandler extends Handler {
this.mActivity = activity;
}
- public KeychainIntentServiceHandler(Activity activity, ProgressDialogFragment progressDialogFragment) {
+ public KeychainIntentServiceHandler(Activity activity,
+ ProgressDialogFragment progressDialogFragment) {
this.mActivity = activity;
this.mProgressDialogFragment = progressDialogFragment;
}
- public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, int progressDialogStyle) {
- this(activity, progressDialogMessageId, progressDialogStyle, false, null);
+ public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage,
+ int progressDialogStyle) {
+ this(activity, progressDialogMessage, progressDialogStyle, false, null);
}
- public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId,
+ public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage,
int progressDialogStyle, boolean cancelable,
OnCancelListener onCancelListener) {
this.mActivity = activity;
- this.mProgressDialogFragment = ProgressDialogFragment.newInstance(progressDialogMessageId,
- progressDialogStyle, cancelable, onCancelListener);
+ this.mProgressDialogFragment = ProgressDialogFragment.newInstance(
+ progressDialogMessage,
+ progressDialogStyle,
+ cancelable,
+ onCancelListener);
}
public void showProgressDialog(FragmentActivity activity) {
- // TODO: This is a hack!, see http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
+ // TODO: This is a hack!, see
+ // http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
final FragmentManager manager = activity.getSupportFragmentManager();
Handler handler = new Handler();
handler.post(new Runnable() {
@@ -84,43 +88,43 @@ public class KeychainIntentServiceHandler extends Handler {
Bundle data = message.getData();
switch (message.arg1) {
- case MESSAGE_OKAY:
- mProgressDialogFragment.dismissAllowingStateLoss();
+ case MESSAGE_OKAY:
+ mProgressDialogFragment.dismissAllowingStateLoss();
- break;
+ break;
- case MESSAGE_EXCEPTION:
- mProgressDialogFragment.dismissAllowingStateLoss();
+ case MESSAGE_EXCEPTION:
+ mProgressDialogFragment.dismissAllowingStateLoss();
- // show error from service
- if (data.containsKey(DATA_ERROR)) {
- Toast.makeText(mActivity,
- mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)),
- Toast.LENGTH_SHORT).show();
- }
+ // show error from service
+ if (data.containsKey(DATA_ERROR)) {
+ Toast.makeText(mActivity,
+ mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)),
+ Toast.LENGTH_SHORT).show();
+ }
- break;
-
- case MESSAGE_UPDATE_PROGRESS:
- if (data.containsKey(DATA_PROGRESS) && data.containsKey(DATA_PROGRESS_MAX)) {
-
- // update progress from service
- if (data.containsKey(DATA_MESSAGE)) {
- mProgressDialogFragment.setProgress(data.getString(DATA_MESSAGE),
- data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX));
- } else if (data.containsKey(DATA_MESSAGE_ID)) {
- mProgressDialogFragment.setProgress(data.getInt(DATA_MESSAGE_ID),
- data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX));
- } else {
- mProgressDialogFragment.setProgress(data.getInt(DATA_PROGRESS),
- data.getInt(DATA_PROGRESS_MAX));
+ break;
+
+ case MESSAGE_UPDATE_PROGRESS:
+ if (data.containsKey(DATA_PROGRESS) && data.containsKey(DATA_PROGRESS_MAX)) {
+
+ // update progress from service
+ if (data.containsKey(DATA_MESSAGE)) {
+ mProgressDialogFragment.setProgress(data.getString(DATA_MESSAGE),
+ data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX));
+ } else if (data.containsKey(DATA_MESSAGE_ID)) {
+ mProgressDialogFragment.setProgress(data.getInt(DATA_MESSAGE_ID),
+ data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX));
+ } else {
+ mProgressDialogFragment.setProgress(data.getInt(DATA_PROGRESS),
+ data.getInt(DATA_PROGRESS_MAX));
+ }
}
- }
- break;
+ break;
- default:
- break;
+ default:
+ break;
}
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index abd2320e3..5825db01b 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -17,10 +17,16 @@
package org.sufficientlysecure.keychain.service;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.*;
+import android.util.Log;
+import android.support.v4.util.LongSparseArray;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -33,28 +39,13 @@ import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
+import java.util.Date;
+import java.util.Iterator;
/**
* This service runs in its own process, but is available to all other processes as the main
* passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for
* convenience.
- *
*/
public class PassphraseCacheService extends Service {
public static final String TAG = Constants.TAG + ": PassphraseCacheService";
@@ -77,7 +68,7 @@ public class PassphraseCacheService extends Service {
private BroadcastReceiver mIntentReceiver;
- private HashMap<Long, String> mPassphraseCache = new HashMap<Long, String>();
+ private LongSparseArray<String> mPassphraseCache = new LongSparseArray<String>();
Context mContext;
@@ -85,7 +76,7 @@ public class PassphraseCacheService extends Service {
* This caches a new passphrase in memory by sending a new command to the service. An android
* service is only run once. Thus, when the service is already started, new commands just add
* new events to the alarm manager for new passphrases to let them timeout in the future.
- *
+ *
* @param context
* @param keyId
* @param passphrase
@@ -105,7 +96,7 @@ public class PassphraseCacheService extends Service {
/**
* Gets a cached passphrase from memory by sending an intent to the service. This method is
* designed to wait until the service returns the passphrase.
- *
+ *
* @param context
* @param keyId
* @return passphrase or null (if no passphrase is cached for this keyId)
@@ -160,7 +151,7 @@ public class PassphraseCacheService extends Service {
/**
* Internal implementation to get cached passphrase.
- *
+ *
* @param keyId
* @return
*/
@@ -204,7 +195,7 @@ public class PassphraseCacheService extends Service {
/**
* Checks if key has a passphrase.
- *
+ *
* @param secretKeyId
* @return true if it has a passphrase
*/
@@ -215,17 +206,17 @@ public class PassphraseCacheService extends Service {
.getPGPSecretKeyRingByKeyId(context, secretKeyId);
PGPSecretKey secretKey = null;
boolean foundValidKey = false;
- for (Iterator keys = secRing.getSecretKeys(); keys.hasNext();) {
- secretKey = (PGPSecretKey)keys.next();
+ for (Iterator keys = secRing.getSecretKeys(); keys.hasNext(); ) {
+ secretKey = (PGPSecretKey) keys.next();
if (!secretKey.isPrivateKeyEmpty()) {
foundValidKey = true;
break;
}
}
- if (!foundValidKey)
+ if (!foundValidKey) {
return false;
-
+ }
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
"SC").build("".toCharArray());
PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
@@ -268,7 +259,7 @@ public class PassphraseCacheService extends Service {
/**
* Build pending intent that is executed by alarm manager to time out a specific passphrase
- *
+ *
* @param context
* @param keyId
* @return
@@ -336,7 +327,7 @@ public class PassphraseCacheService extends Service {
/**
* Called when one specific passphrase for keyId timed out
- *
+ *
* @param context
* @param keyId
*/
@@ -347,7 +338,7 @@ public class PassphraseCacheService extends Service {
Log.d(TAG, "Timeout of keyId " + keyId + ", removed from memory!");
// stop whole service if no cached passphrases remaining
- if (mPassphraseCache.isEmpty()) {
+ if (mPassphraseCache.size() == 0) {
Log.d(TAG, "No passphrases remaining in memory, stopping service!");
stopSelf();
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java
deleted file mode 100644
index 64c4c5e96..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java
+++ /dev/null
@@ -1,243 +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.service.remote;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import org.spongycastle.util.encoders.Hex;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
-import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
-import org.sufficientlysecure.keychain.util.AlgorithmNames;
-import org.sufficientlysecure.keychain.util.Log;
-
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import com.beardedhen.androidbootstrap.BootstrapButton;
-
-public class AppSettingsFragment extends Fragment implements
- SelectSecretKeyLayoutFragment.SelectSecretKeyCallback {
-
- // model
- private AppSettings appSettings;
-
- // view
- private LinearLayout mAdvancedSettingsContainer;
- private BootstrapButton mAdvancedSettingsButton;
- private TextView mAppNameView;
- private ImageView mAppIconView;
- private Spinner mEncryptionAlgorithm;
- private Spinner mHashAlgorithm;
- private Spinner mCompression;
- private TextView mPackageName;
- private TextView mPackageSignature;
-
- private SelectSecretKeyLayoutFragment mSelectKeyFragment;
-
- KeyValueSpinnerAdapter encryptionAdapter;
- KeyValueSpinnerAdapter hashAdapter;
- KeyValueSpinnerAdapter compressionAdapter;
-
- public AppSettings getAppSettings() {
- return appSettings;
- }
-
- public void setAppSettings(AppSettings appSettings) {
- this.appSettings = appSettings;
- setPackage(appSettings.getPackageName());
- mPackageName.setText(appSettings.getPackageName());
-
- try {
- MessageDigest md = MessageDigest.getInstance("SHA-256");
- md.update(appSettings.getPackageSignature());
- byte[] digest = md.digest();
- String signature = new String(Hex.encode(digest));
-
- mPackageSignature.setText(signature);
- } catch (NoSuchAlgorithmException e) {
- Log.e(Constants.TAG, "Should not happen!", e);
- }
-
- mSelectKeyFragment.selectKey(appSettings.getKeyId());
- mEncryptionAlgorithm.setSelection(encryptionAdapter.getPosition(appSettings
- .getEncryptionAlgorithm()));
- mHashAlgorithm.setSelection(hashAdapter.getPosition(appSettings.getHashAlgorithm()));
- mCompression.setSelection(compressionAdapter.getPosition(appSettings.getCompression()));
- }
-
- /**
- * Inflate the layout for this fragment
- */
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.api_app_settings_fragment, container, false);
- initView(view);
- return view;
- }
-
- /**
- * Set error String on key selection
- *
- * @param error
- */
- public void setErrorOnSelectKeyFragment(String error) {
- mSelectKeyFragment.setError(error);
- }
-
- private void initView(View view) {
- mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getFragmentManager().findFragmentById(
- R.id.api_app_settings_select_key_fragment);
- mSelectKeyFragment.setCallback(this);
-
- mAdvancedSettingsButton = (BootstrapButton) view
- .findViewById(R.id.api_app_settings_advanced_button);
- mAdvancedSettingsContainer = (LinearLayout) view
- .findViewById(R.id.api_app_settings_advanced);
-
- mAppNameView = (TextView) view.findViewById(R.id.api_app_settings_app_name);
- mAppIconView = (ImageView) view.findViewById(R.id.api_app_settings_app_icon);
- mEncryptionAlgorithm = (Spinner) view
- .findViewById(R.id.api_app_settings_encryption_algorithm);
- mHashAlgorithm = (Spinner) view.findViewById(R.id.api_app_settings_hash_algorithm);
- mCompression = (Spinner) view.findViewById(R.id.api_app_settings_compression);
- mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name);
- mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature);
-
- AlgorithmNames algorithmNames = new AlgorithmNames(getActivity());
-
- encryptionAdapter = new KeyValueSpinnerAdapter(getActivity(),
- algorithmNames.getEncryptionNames());
- mEncryptionAlgorithm.setAdapter(encryptionAdapter);
- mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- appSettings.setEncryptionAlgorithm((int) id);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
- hashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames());
- mHashAlgorithm.setAdapter(hashAdapter);
- mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- appSettings.setHashAlgorithm((int) id);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
- compressionAdapter = new KeyValueSpinnerAdapter(getActivity(),
- algorithmNames.getCompressionNames());
- mCompression.setAdapter(compressionAdapter);
- mCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- appSettings.setCompression((int) id);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
-
- final Animation visibleAnimation = new AlphaAnimation(0.0f, 1.0f);
- visibleAnimation.setDuration(250);
- final Animation invisibleAnimation = new AlphaAnimation(1.0f, 0.0f);
- invisibleAnimation.setDuration(250);
-
- // TODO: Better: collapse/expand animation
- // final Animation animation2 = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
- // Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f,
- // Animation.RELATIVE_TO_SELF, 0.0f);u
- // animation2.setDuration(150);
-
- mAdvancedSettingsButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (mAdvancedSettingsContainer.getVisibility() == View.VISIBLE) {
- mAdvancedSettingsContainer.startAnimation(invisibleAnimation);
- mAdvancedSettingsContainer.setVisibility(View.GONE);
- mAdvancedSettingsButton.setText(getString(R.string.api_settings_show_advanced));
- mAdvancedSettingsButton.setLeftIcon("fa-caret-up");
- } else {
- mAdvancedSettingsContainer.startAnimation(visibleAnimation);
- mAdvancedSettingsContainer.setVisibility(View.VISIBLE);
- mAdvancedSettingsButton.setText(getString(R.string.api_settings_hide_advanced));
- mAdvancedSettingsButton.setLeftIcon("fa-caret-down");
- }
- }
- });
- }
-
- private void setPackage(String packageName) {
- PackageManager pm = getActivity().getApplicationContext().getPackageManager();
-
- // get application name and icon from package manager
- String appName = null;
- Drawable appIcon = null;
- try {
- ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
-
- appName = (String) pm.getApplicationLabel(ai);
- appIcon = pm.getApplicationIcon(ai);
- } catch (final NameNotFoundException e) {
- // fallback
- appName = packageName;
- }
- mAppNameView.setText(appName);
- mAppIconView.setImageDrawable(appIcon);
- }
-
- /**
- * callback from select secret key fragment
- */
- @Override
- public void onKeySelected(long secretKeyId) {
- appSettings.setKeyId(secretKeyId);
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsAdapter.java
deleted file mode 100644
index 477ee04d0..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsAdapter.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 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.service.remote;
-
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.database.Cursor;
-import android.support.v4.widget.CursorAdapter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-public class RegisteredAppsAdapter extends CursorAdapter {
-
- private LayoutInflater mInflater;
- private PackageManager pm;
-
- public RegisteredAppsAdapter(Context context, Cursor c, int flags) {
- super(context, c, flags);
-
- mInflater = LayoutInflater.from(context);
- pm = context.getApplicationContext().getPackageManager();
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name);
- ImageView icon = (ImageView) view.findViewById(R.id.api_apps_adapter_item_icon);
-
- String packageName = cursor.getString(cursor.getColumnIndex(ApiApps.PACKAGE_NAME));
- if (packageName != null) {
- // get application name
- try {
- ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
-
- text.setText(pm.getApplicationLabel(ai));
- icon.setImageDrawable(pm.getApplicationIcon(ai));
- } catch (final NameNotFoundException e) {
- // fallback
- text.setText(packageName);
- }
- } else {
- // fallback
- text.setText(packageName);
- }
-
- }
-
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.api_apps_adapter_list_item, null);
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java
deleted file mode 100644
index cc08548e8..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.sufficientlysecure.keychain.service.remote;
-
-public class WrongPackageSignatureException extends Exception {
-
- private static final long serialVersionUID = -8294642703122196028L;
-
- public WrongPackageSignatureException(String message) {
- super(message);
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
index aab6b81d9..5dc06c16d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
@@ -17,47 +17,47 @@
package org.sufficientlysecure.keychain.ui;
-import java.util.Iterator;
-
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.ProgressDialog;
import android.content.Intent;
+import android.database.Cursor;
import android.net.Uri;
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;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
+import android.widget.*;
import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.Spinner;
-import android.widget.Toast;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.OtherHelper;
+import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
+import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.ArrayList;
/**
* Signs the specified public key with the specified secret master key
*/
public class CertifyKeyActivity extends ActionBarActivity implements
- SelectSecretKeyLayoutFragment.SelectSecretKeyCallback {
+ SelectSecretKeyLayoutFragment.SelectSecretKeyCallback, LoaderManager.LoaderCallbacks<Cursor> {
private BootstrapButton mSignButton;
private CheckBox mUploadKeyCheckbox;
private Spinner mSelectKeyserverSpinner;
@@ -68,6 +68,12 @@ public class CertifyKeyActivity extends ActionBarActivity implements
private long mPubKeyId = 0;
private long mMasterKeyId = 0;
+ private ListView mUserIds;
+ private ViewKeyUserIdsAdapter mUserIdsAdapter;
+
+ private static final int LOADER_ID_KEYRING = 0;
+ private static final int LOADER_ID_USER_IDS = 1;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -87,7 +93,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
mSelectKeyserverSpinner = (Spinner) findViewById(R.id.sign_key_keyserver);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
- .getKeyServers());
+ .getKeyServers());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSelectKeyserverSpinner.setAdapter(adapter);
@@ -131,9 +137,18 @@ public class CertifyKeyActivity extends ActionBarActivity implements
finish();
return;
}
+ Log.e(Constants.TAG, "uri: " + mDataUri);
PGPPublicKeyRing signKey = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, mDataUri);
+ mUserIds = (ListView) findViewById(R.id.user_ids);
+
+ mUserIdsAdapter = new ViewKeyUserIdsAdapter(this, null, 0, true);
+ mUserIds.setAdapter(mUserIdsAdapter);
+
+ getSupportLoaderManager().initLoader(LOADER_ID_KEYRING, null, this);
+ getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
+
if (signKey != null) {
mPubKeyId = PgpKeyHelper.getMasterKey(signKey).getKeyID();
}
@@ -144,6 +159,78 @@ public class CertifyKeyActivity extends ActionBarActivity implements
}
}
+ static final String[] KEYRING_PROJECTION =
+ new String[] {
+ KeychainContract.KeyRings._ID,
+ KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.Keys.FINGERPRINT,
+ KeychainContract.UserIds.USER_ID
+ };
+ static final int INDEX_MASTER_KEY_ID = 1;
+ static final int INDEX_FINGERPRINT = 2;
+ static final int INDEX_USER_ID = 3;
+
+ static final String[] USER_IDS_PROJECTION =
+ new String[]{
+ KeychainContract.UserIds._ID,
+ KeychainContract.UserIds.USER_ID,
+ KeychainContract.UserIds.RANK
+ };
+ static final String USER_IDS_SORT_ORDER =
+ KeychainContract.UserIds.RANK + " ASC";
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ switch(id) {
+ case LOADER_ID_KEYRING:
+ return new CursorLoader(this, mDataUri, KEYRING_PROJECTION, null, null, null);
+ case LOADER_ID_USER_IDS: {
+ Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri);
+ return new CursorLoader(this, baseUri, USER_IDS_PROJECTION, null, null, USER_IDS_SORT_ORDER);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ switch(loader.getId()) {
+ case LOADER_ID_KEYRING:
+ // the first key here is our master key
+ if (data.moveToFirst()) {
+ // TODO: put findViewById in onCreate!
+
+ long keyId = data.getLong(INDEX_MASTER_KEY_ID);
+ String keyIdStr = PgpKeyHelper.convertKeyIdToHexShort(keyId);
+ ((TextView) findViewById(R.id.key_id)).setText(keyIdStr);
+
+ String mainUserId = data.getString(INDEX_USER_ID);
+ ((TextView) findViewById(R.id.main_user_id)).setText(mainUserId);
+
+ byte[] fingerprintBlob = data.getBlob(INDEX_FINGERPRINT);
+ if (fingerprintBlob == null) {
+ // FALLBACK for old database entries
+ fingerprintBlob = ProviderHelper.getFingerprint(this, mDataUri);
+ }
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
+ ((TextView) findViewById(R.id.fingerprint)).setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
+ }
+ break;
+ case LOADER_ID_USER_IDS:
+ mUserIdsAdapter.swapCursor(data);
+ break;
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ switch(loader.getId()) {
+ case LOADER_ID_USER_IDS:
+ mUserIdsAdapter.swapCursor(null);
+ break;
+ }
+ }
+
private void showPassphraseDialog(final long secretKeyId) {
// Message is received after passphrase is cached
Handler returnHandler = new Handler() {
@@ -179,6 +266,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
// if we have already signed this key, dont bother doing it again
boolean alreadySigned = false;
+ /* todo: reconsider this at a later point when certs are in the db
@SuppressWarnings("unchecked")
Iterator<PGPSignature> itr = pubring.getPublicKey(mPubKeyId).getSignatures();
while (itr.hasNext()) {
@@ -188,6 +276,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
break;
}
}
+ */
if (!alreadySigned) {
/*
@@ -215,6 +304,15 @@ public class CertifyKeyActivity extends ActionBarActivity implements
* kicks off the actual signing process on a background thread
*/
private void startSigning() {
+
+ // Bail out if there is not at least one user id selected
+ ArrayList<String> userIds = mUserIdsAdapter.getSelectedUserIds();
+ if(userIds.isEmpty()) {
+ Toast.makeText(CertifyKeyActivity.this, "No User IDs to sign selected!",
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
// Send all information needed to service to sign key in other thread
Intent intent = new Intent(this, KeychainIntentService.class);
@@ -225,14 +323,15 @@ public class CertifyKeyActivity extends ActionBarActivity implements
data.putLong(KeychainIntentService.CERTIFY_KEY_MASTER_KEY_ID, mMasterKeyId);
data.putLong(KeychainIntentService.CERTIFY_KEY_PUB_KEY_ID, mPubKeyId);
+ data.putStringArrayList(KeychainIntentService.CERTIFY_KEY_UIDS, userIds);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after signing is done in ApgService
+ // Message is received after signing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- R.string.progress_signing, ProgressDialog.STYLE_SPINNER) {
+ getString(R.string.progress_signing), ProgressDialog.STYLE_SPINNER) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -249,7 +348,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
finish();
}
}
- };
+ }
};
// Create a new Messenger for the communication back
@@ -281,11 +380,11 @@ public class CertifyKeyActivity extends ActionBarActivity implements
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after uploading is done in ApgService
+ // Message is received after uploading is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) {
+ getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -295,7 +394,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
setResult(RESULT_OK);
finish();
}
- };
+ }
};
// Create a new Messenger for the communication back
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 42288ca37..9b3b00c19 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -17,14 +17,20 @@
package org.sufficientlysecure.keychain.ui;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.util.regex.Matcher;
-
+import android.annotation.SuppressLint;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.animation.AnimationUtils;
+import android.widget.*;
+import com.beardedhen.androidbootstrap.BootstrapButton;
+import com.devspark.appmsg.AppMsg;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.sufficientlysecure.keychain.Constants;
@@ -33,10 +39,10 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -48,27 +54,8 @@ import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import android.annotation.SuppressLint;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.animation.AnimationUtils;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.widget.ViewFlipper;
-
-import com.beardedhen.androidbootstrap.BootstrapButton;
-import com.devspark.appmsg.AppMsg;
+import java.io.*;
+import java.util.regex.Matcher;
@SuppressLint("NewApi")
public class DecryptActivity extends DrawerActivity {
@@ -364,7 +351,7 @@ public class DecryptActivity extends DrawerActivity {
}
} else {
Log.e(Constants.TAG,
- "Direct binary data without actual file in filesystem is not supported. Please use the Remote Service API!");
+ "Direct binary data without actual file in filesystem is not supported. Please use the Remote Service API!");
Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG)
.show();
// end activity
@@ -383,7 +370,7 @@ public class DecryptActivity extends DrawerActivity {
if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) {
filename = filename.substring(0, filename.length() - 4);
}
- mOutputFilename = Constants.path.APP_DIR + "/" + filename;
+ mOutputFilename = Constants.Path.APP_DIR + "/" + filename;
}
private void updateSource() {
@@ -456,8 +443,7 @@ public class DecryptActivity extends DrawerActivity {
getDecryptionKeyFromInputStream();
// if we need a symmetric passphrase or a passphrase to use a secret key ask for it
- if (mSecretKeyId == Id.key.symmetric
- || PassphraseCacheService.getCachedPassphrase(this, mSecretKeyId) == null) {
+ if (mAssumeSymmetricEncryption || PassphraseCacheService.getCachedPassphrase(this, mSecretKeyId) == null) {
showPassphraseDialog();
} else {
if (mDecryptTarget == Id.target.file) {
@@ -507,6 +493,7 @@ public class DecryptActivity extends DrawerActivity {
* TODO: Rework function, remove global variables
*/
private void getDecryptionKeyFromInputStream() {
+ mAssumeSymmetricEncryption = false;
InputStream inStream = null;
if (mContentUri != null) {
try {
@@ -546,7 +533,6 @@ public class DecryptActivity extends DrawerActivity {
if (mSecretKeyId == Id.key.none) {
throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
}
- mAssumeSymmetricEncryption = false;
} catch (NoAsymmetricEncryptionException e) {
if (inStream.markSupported()) {
inStream.reset();
@@ -559,6 +545,7 @@ public class DecryptActivity extends DrawerActivity {
mAssumeSymmetricEncryption = true;
}
} catch (Exception e) {
+ Log.e(Constants.TAG, "error while reading decryption key from input stream", e);
AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
AppMsg.STYLE_ALERT).show();
}
@@ -644,11 +631,11 @@ public class DecryptActivity extends DrawerActivity {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after encrypting is done in ApgService
+ // Message is received after encrypting is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- R.string.progress_decrypting, ProgressDialog.STYLE_HORIZONTAL) {
+ getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -744,8 +731,6 @@ public class DecryptActivity extends DrawerActivity {
}
}
}
-
- ;
};
// Create a new Messenger for the communication back
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java
index 08ca262c3..f01e67449 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java
@@ -17,30 +17,21 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
+import android.view.*;
+import android.widget.*;
import com.beardedhen.androidbootstrap.FontAwesomeText;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
public class DrawerActivity extends ActionBarActivity {
private DrawerLayout mDrawerLayout;
@@ -49,10 +40,8 @@ public class DrawerActivity extends ActionBarActivity {
private CharSequence mDrawerTitle;
private CharSequence mTitle;
+ private boolean mIsDrawerLocked = false;
- private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class,
- EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class,
- KeyListSecretActivity.class, RegisteredAppsListActivity.class };
private Class mSelectedItem;
private static final int MENU_ID_PREFERENCE = 222;
@@ -62,18 +51,29 @@ public class DrawerActivity extends ActionBarActivity {
mDrawerTitle = getString(R.string.app_name);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
+ ViewGroup viewGroup = (ViewGroup) findViewById(R.id.content_frame);
+ int leftMarginLoaded = ((ViewGroup.MarginLayoutParams) viewGroup.getLayoutParams()).leftMargin;
+ int leftMarginInTablets = (int) getResources().getDimension(R.dimen.drawer_size);
+ int errorInMarginAllowed = 5;
+
+ // if the left margin of the loaded layout is close to the
+ // one used in tablets then set drawer as open and locked
+ if( Math.abs(leftMarginLoaded - leftMarginInTablets) < errorInMarginAllowed) {
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN, mDrawerList);
+ mDrawerLayout.setScrimColor(Color.TRANSPARENT);
+ mIsDrawerLocked = true;
+ } else {
+ // set a custom shadow that overlays the main content when the drawer opens
+ mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
+ mIsDrawerLocked = false;
+ }
- // set a custom shadow that overlays the main content when the drawer
- // opens
- mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
-
- NavItem mItemIconTexts[] = new NavItem[] {
+ NavItem mItemIconTexts[] = new NavItem[]{
new NavItem("fa-user", getString(R.string.nav_contacts)),
new NavItem("fa-lock", getString(R.string.nav_encrypt)),
new NavItem("fa-unlock", getString(R.string.nav_decrypt)),
new NavItem("fa-download", getString(R.string.nav_import)),
- new NavItem("fa-key", getString(R.string.nav_secret_keys)),
- new NavItem("fa-android", getString(R.string.nav_apps)) };
+ new NavItem("fa-android", getString(R.string.nav_apps))};
mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item,
mItemIconTexts));
@@ -81,32 +81,24 @@ public class DrawerActivity extends ActionBarActivity {
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setHomeButtonEnabled(true);
+ // if the drawer is not locked
+ if ( !mIsDrawerLocked ) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+ }
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
- mDrawerLayout, /* DrawerLayout object */
- R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
- R.string.drawer_open, /* "open drawer" description for accessibility */
- R.string.drawer_close /* "close drawer" description for accessibility */
+ mDrawerLayout, /* DrawerLayout object */
+ R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
+ R.string.drawer_open, /* "open drawer" description for accessibility */
+ R.string.drawer_close /* "close drawer" description for accessibility */
) {
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
- // creates call to onPrepareOptionsMenu()
- supportInvalidateOptionsMenu();
-
- // call intent activity if selected
- if(mSelectedItem != null) {
- finish();
- overridePendingTransition(0, 0);
- Intent intent = new Intent(DrawerActivity.this, mSelectedItem);
- startActivity(intent);
- // disable animation of activity start
- overridePendingTransition(0, 0);
- }
+ callIntentForDrawerItem(mSelectedItem);
}
public void onDrawerOpened(View drawerView) {
@@ -116,13 +108,40 @@ public class DrawerActivity extends ActionBarActivity {
supportInvalidateOptionsMenu();
}
};
- mDrawerLayout.setDrawerListener(mDrawerToggle);
+ if ( !mIsDrawerLocked ) {
+ mDrawerLayout.setDrawerListener(mDrawerToggle);
+ } else {
+ // If the drawer is locked open make it un-focusable
+ // so that it doesn't consume all the Back button presses
+ mDrawerLayout.setFocusableInTouchMode(false);
+ }
// if (savedInstanceState == null) {
// selectItem(0);
// }
}
+ /**
+ * Uses startActivity to call the Intent of the given class
+ * @param drawerItem the class of the drawer item you want to load. Based on Constants.DrawerItems.*
+ */
+ public void callIntentForDrawerItem(Class drawerItem) {
+ // creates call to onPrepareOptionsMenu()
+ supportInvalidateOptionsMenu();
+
+ // call intent activity if selected
+ if (drawerItem != null) {
+ finish();
+ overridePendingTransition(0, 0);
+
+ Intent intent = new Intent(this, drawerItem);
+ startActivity(intent);
+
+ // disable animation of activity start
+ overridePendingTransition(0, 0);
+ }
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(42, MENU_ID_PREFERENCE, 100, R.string.menu_preferences);
@@ -150,18 +169,18 @@ public class DrawerActivity extends ActionBarActivity {
}
switch (item.getItemId()) {
- case MENU_ID_PREFERENCE: {
- Intent intent = new Intent(this, PreferencesActivity.class);
- startActivity(intent);
- return true;
- }
- case MENU_ID_HELP: {
- Intent intent = new Intent(this, HelpActivity.class);
- startActivity(intent);
- return true;
- }
- default:
- return super.onOptionsItemSelected(item);
+ case MENU_ID_PREFERENCE: {
+ Intent intent = new Intent(this, PreferencesActivity.class);
+ startActivity(intent);
+ return true;
+ }
+ case MENU_ID_HELP: {
+ Intent intent = new Intent(this, HelpActivity.class);
+ startActivity(intent);
+ return true;
+ }
+ default:
+ return super.onOptionsItemSelected(item);
}
// Handle action buttons
@@ -193,10 +212,18 @@ public class DrawerActivity extends ActionBarActivity {
private void selectItem(int position) {
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
- // setTitle(mDrawerTitles[position]);
- mDrawerLayout.closeDrawer(mDrawerList);
// set selected class
- mSelectedItem = mItemsClass[position];
+ mSelectedItem = Constants.DrawerItems.ARRAY[position];
+
+ // setTitle(mDrawerTitles[position]);
+ // If drawer isn't locked just close the drawer and
+ // it will move to the selected item by itself (via drawer toggle listener)
+ if ( !mIsDrawerLocked ) {
+ mDrawerLayout.closeDrawer(mDrawerList);
+ // else move to the selected item yourself
+ } else {
+ callIntentForDrawerItem(mSelectedItem);
+ }
}
/**
@@ -229,15 +256,15 @@ public class DrawerActivity extends ActionBarActivity {
}
private class NavigationDrawerAdapter extends ArrayAdapter<NavItem> {
- Context context;
- int layoutResourceId;
- NavItem data[] = null;
+ Context mContext;
+ int mLayoutResourceId;
+ NavItem mData[] = null;
public NavigationDrawerAdapter(Context context, int layoutResourceId, NavItem[] data) {
super(context, layoutResourceId, data);
- this.layoutResourceId = layoutResourceId;
- this.context = context;
- this.data = data;
+ this.mLayoutResourceId = layoutResourceId;
+ this.mContext = context;
+ this.mData = data;
}
@Override
@@ -246,21 +273,21 @@ public class DrawerActivity extends ActionBarActivity {
NavItemHolder holder = null;
if (row == null) {
- LayoutInflater inflater = ((Activity) context).getLayoutInflater();
- row = inflater.inflate(layoutResourceId, parent, false);
+ LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
+ row = inflater.inflate(mLayoutResourceId, parent, false);
holder = new NavItemHolder();
- holder.img = (FontAwesomeText) row.findViewById(R.id.drawer_item_icon);
- holder.txtTitle = (TextView) row.findViewById(R.id.drawer_item_text);
+ holder.mImg = (FontAwesomeText) row.findViewById(R.id.drawer_item_icon);
+ holder.mTxtTitle = (TextView) row.findViewById(R.id.drawer_item_text);
row.setTag(holder);
} else {
holder = (NavItemHolder) row.getTag();
}
- NavItem item = data[position];
- holder.txtTitle.setText(item.title);
- holder.img.setIcon(item.icon);
+ NavItem item = mData[position];
+ holder.mTxtTitle.setText(item.title);
+ holder.mImg.setIcon(item.icon);
return row;
}
@@ -268,8 +295,8 @@ public class DrawerActivity extends ActionBarActivity {
}
static class NavItemHolder {
- FontAwesomeText img;
- TextView txtTitle;
+ FontAwesomeText mImg;
+ TextView mTxtTitle;
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
index 0726897c3..b7fffc7ff 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
@@ -23,6 +23,25 @@ import java.util.List;
import java.util.Vector;
import org.spongycastle.bcpg.sig.KeyFlags;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v7.app.ActionBarActivity;
+import android.view.*;
+import android.view.View.OnClickListener;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
@@ -32,6 +51,7 @@ import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
@@ -49,31 +69,12 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import android.app.AlertDialog;
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.ActivityCompat;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import com.beardedhen.androidbootstrap.BootstrapButton;
public class EditKeyActivity extends ActionBarActivity implements EditorListener {
@@ -113,7 +114,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
Vector<String> mUserIds;
Vector<PGPSecretKey> mKeys;
Vector<Integer> mKeysUsages;
- boolean masterCanSign = true;
+ boolean mMasterCanSign = true;
ExportHelper mExportHelper;
@@ -169,7 +170,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
/**
* Handle intent action to create new key
- *
+ *
* @param intent
*/
private void handleActionCreateKey(Intent intent) {
@@ -211,9 +212,10 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after generating is done in ApgService
+ // Message is received after generating is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
- this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER, true,
+ this, getResources().getQuantityString(R.plurals.progress_generating, 1),
+ ProgressDialog.STYLE_HORIZONTAL, true,
new DialogInterface.OnCancelListener() {
@Override
@@ -227,7 +229,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
@Override
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -272,7 +274,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
/**
* Handle intent action to edit existing key
- *
+ *
* @param intent
*/
private void handleActionEditKey(Intent intent) {
@@ -283,12 +285,10 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
} else {
Log.d(Constants.TAG, "uri: " + mDataUri);
- long keyRingRowId = Long.valueOf(mDataUri.getLastPathSegment());
-
// get master key id using row id
- long masterKeyId = ProviderHelper.getSecretMasterKeyId(this, keyRingRowId);
+ long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
- masterCanSign = ProviderHelper.getSecretMasterKeyCanCertify(this, keyRingRowId);
+ mMasterCanSign = ProviderHelper.getMasterKeyCanCertify(this, mDataUri);
finallyEdit(masterKeyId);
}
}
@@ -350,11 +350,16 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
if (needsSaving()) {
Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
} else {
- mExportHelper.showExportKeysDialog(mDataUri, Id.type.secret_key, Constants.path.APP_DIR
- + "/secexport.asc");
+ long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
+ long[] ids = new long[]{masterKeyId};
+ mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC,
+ null);
+ return true;
}
return true;
- case R.id.menu_key_edit_delete: {
+ case R.id.menu_key_edit_delete:
+ long rowId= ProviderHelper.getRowId(this,mDataUri);
+ Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(Long.toString(rowId));
// Message is received after key is deleted
Handler returnHandler = new Handler() {
@Override
@@ -363,12 +368,10 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
setResult(RESULT_CANCELED);
finish();
}
- }
- };
-
- mExportHelper.deleteKey(mDataUri, Id.type.secret_key, returnHandler);
+ }};
+ mExportHelper.deleteKey(convertUri, returnHandler);
return true;
- }
+
case R.id.menu_key_edit_save:
saveClicked();
return true;
@@ -407,8 +410,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
}
mCurrentPassphrase = "";
-
buildLayout(false);
+
mIsPassPhraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId);
if (!mIsPassPhraseSet) {
// check "no passphrase" checkbox and remove button
@@ -466,20 +469,23 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
// find views
mChangePassphrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_passphrase);
mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase);
-
// Build layout based on given userIds and keys
+
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container);
+ if(mIsPassPhraseSet){
+ mChangePassphrase.setText(getString(R.string.btn_change_passphrase));
+ }
mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
mUserIdsView.setType(Id.type.user_id);
- mUserIdsView.setCanEdit(masterCanSign);
+ mUserIdsView.setCanEdit(mMasterCanSign);
mUserIdsView.setUserIds(mUserIds);
mUserIdsView.setEditorListener(this);
container.addView(mUserIdsView);
mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
mKeysView.setType(Id.type.key);
- mKeysView.setCanEdit(masterCanSign);
+ mKeysView.setCanEdit(mMasterCanSign);
mKeysView.setKeys(mKeys, mKeysUsages, newKeys);
mKeysView.setEditorListener(this);
container.addView(mKeysView);
@@ -602,17 +608,16 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
// fill values for this action
Bundle data = new Bundle();
-
- data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, masterCanSign);
+ data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, mMasterCanSign);
data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after saving is done in ApgService
+ // Message is received after saving is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- R.string.progress_saving, ProgressDialog.STYLE_HORIZONTAL) {
+ getString(R.string.progress_saving), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -640,8 +645,9 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
// start service with intent
startService(intent);
} catch (PgpGeneralException e) {
+ Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
Toast.makeText(this, getString(R.string.error_message, e.getMessage()),
- Toast.LENGTH_SHORT).show();
+ Toast.LENGTH_SHORT).show();
}
}
@@ -679,7 +685,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
/**
* Returns user ids from the SectionView
- *
+ *
* @param userIdsView
* @return
*/
@@ -692,11 +698,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
for (int i = 0; i < userIdEditors.getChildCount(); ++i) {
UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i);
String userId;
- try {
- userId = editor.getValue();
- } catch (UserIdEditor.InvalidEmailException e) {
- throw new PgpGeneralException(e.getMessage());
- }
+ userId = editor.getValue();
if (editor.isMainUserId()) {
userIds.add(0, userId);
@@ -719,7 +721,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
/**
* Returns keys from the SectionView
- *
+ *
* @param keysView
* @return
*/
@@ -742,7 +744,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
/**
* Returns usage selections of keys from the SectionView
- *
+ *
* @param keysView
* @return
*/
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
index faac9b157..4f18f69d7 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
@@ -17,9 +17,22 @@
package org.sufficientlysecure.keychain.ui;
-import java.io.File;
-import java.util.Vector;
-
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.*;
+import com.beardedhen.androidbootstrap.BootstrapButton;
+import com.beardedhen.androidbootstrap.FontAwesomeText;
+import com.devspark.appmsg.AppMsg;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -43,27 +56,8 @@ import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Choice;
import org.sufficientlysecure.keychain.util.Log;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.animation.AnimationUtils;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.widget.ViewFlipper;
-
-import com.beardedhen.androidbootstrap.BootstrapButton;
-import com.devspark.appmsg.AppMsg;
+import java.io.File;
+import java.util.Vector;
public class EncryptActivity extends DrawerActivity {
@@ -108,6 +102,7 @@ public class EncryptActivity extends DrawerActivity {
private EditText mFilename = null;
private CheckBox mDeleteAfter = null;
+ private CheckBox mShareAfter = null;
private BootstrapButton mBrowse = null;
private String mInputFilename = null;
@@ -602,11 +597,11 @@ public class EncryptActivity extends DrawerActivity {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after encrypting is done in ApgService
+ // Message is received after encrypting is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- R.string.progress_encrypting, ProgressDialog.STYLE_HORIZONTAL) {
+ getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -650,6 +645,15 @@ public class EncryptActivity extends DrawerActivity {
.newInstance(mInputFilename);
deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog");
}
+
+ if (mShareAfter.isChecked()) {
+ // Share encrypted file
+ Intent sendFileIntent = new Intent(Intent.ACTION_SEND);
+ sendFileIntent.setType("*/*");
+ sendFileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(mOutputFilename));
+ startActivity(Intent.createChooser(sendFileIntent,
+ getString(R.string.title_send_file)));
+ }
break;
default:
@@ -659,8 +663,6 @@ public class EncryptActivity extends DrawerActivity {
}
}
}
-
- ;
};
// Create a new Messenger for the communication back
@@ -785,6 +787,11 @@ public class EncryptActivity extends DrawerActivity {
}
});
+
+
+
+
+
mFileCompression = (Spinner) findViewById(R.id.fileCompression);
Choice[] choices = new Choice[]{
new Choice(Id.choice.compression.none, getString(R.string.choice_none) + " ("
@@ -794,7 +801,7 @@ public class EncryptActivity extends DrawerActivity {
new Choice(Id.choice.compression.zlib, "ZLIB ("
+ getString(R.string.compression_fast) + ")"),
new Choice(Id.choice.compression.bzip2, "BZIP2 ("
- + getString(R.string.compression_very_slow) + ")"),};
+ + getString(R.string.compression_very_slow) + ")"), };
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(this,
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -809,6 +816,7 @@ public class EncryptActivity extends DrawerActivity {
}
mDeleteAfter = (CheckBox) findViewById(R.id.deleteAfterEncryption);
+ mShareAfter = (CheckBox) findViewById(R.id.shareAfterEncryption);
mAsciiArmor = (CheckBox) findViewById(R.id.asciiArmour);
mAsciiArmor.setChecked(Preferences.getPreferences(this).getDefaultAsciiArmour());
@@ -947,8 +955,8 @@ public class EncryptActivity extends DrawerActivity {
case Id.request.secret_keys: {
if (resultCode == RESULT_OK) {
- Bundle bundle = data.getExtras();
- mSecretKeyId = bundle.getLong(SelectSecretKeyActivity.RESULT_EXTRA_MASTER_KEY_ID);
+ Uri uri_master_key = data.getData();
+ mSecretKeyId = Long.valueOf(uri_master_key.getLastPathSegment());
} else {
mSecretKeyId = Id.key.none;
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
index 12d689274..a484b57de 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java
@@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.htmltextview.HtmlTextView;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -31,6 +26,10 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import org.sufficientlysecure.htmltextview.HtmlTextView;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
public class HelpAboutFragment extends Fragment {
@@ -55,7 +54,7 @@ public class HelpAboutFragment extends Fragment {
/**
* Get the current package version.
- *
+ *
* @return The current version.
*/
private String getVersion() {
@@ -73,4 +72,4 @@ public class HelpAboutFragment extends Fragment {
return result;
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java
index 9ccd7e088..32f37a0a5 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * 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
@@ -17,24 +17,16 @@
package org.sufficientlysecure.keychain.ui;
-import java.util.ArrayList;
-
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
-
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
-import android.widget.TextView;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
public class HelpActivity extends ActionBarActivity {
- public static final String EXTRA_SELECTED_TAB = "selectedTab";
+ public static final String EXTRA_SELECTED_TAB = "selected_tab";
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
@@ -64,19 +56,24 @@ public class HelpActivity extends ActionBarActivity {
Bundle startBundle = new Bundle();
startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)),
- HelpHtmlFragment.class, startBundle, (selectedTab == 0 ? true : false));
+ HelpHtmlFragment.class, startBundle, (selectedTab == 0));
+
+ Bundle faqBundle = new Bundle();
+ faqBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_faq);
+ mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_faq)),
+ HelpHtmlFragment.class, faqBundle, (selectedTab == 1));
Bundle nfcBundle = new Bundle();
nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)),
- HelpHtmlFragment.class, nfcBundle, (selectedTab == 1 ? true : false));
+ HelpHtmlFragment.class, nfcBundle, (selectedTab == 2));
Bundle changelogBundle = new Bundle();
changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)),
- HelpHtmlFragment.class, changelogBundle, (selectedTab == 2 ? true : false));
+ HelpHtmlFragment.class, changelogBundle, (selectedTab == 3));
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)),
- HelpAboutFragment.class, null, (selectedTab == 3 ? true : false));
+ HelpAboutFragment.class, null, (selectedTab == 4));
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java
index 3afb5bbe0..6b3c51b08 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java
@@ -17,8 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.htmltextview.HtmlTextView;
-
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -27,11 +25,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
+import org.sufficientlysecure.htmltextview.HtmlTextView;
public class HelpHtmlFragment extends Fragment {
private Activity mActivity;
- private int htmlFile;
+ private int mHtmlFile;
public static final String ARG_HTML_FILE = "htmlFile";
@@ -52,8 +51,8 @@ public class HelpHtmlFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mActivity = getActivity();
-
- htmlFile = getArguments().getInt(ARG_HTML_FILE);
+
+ mHtmlFile = getArguments().getInt(ARG_HTML_FILE);
ScrollView scroller = new ScrollView(mActivity);
HtmlTextView text = new HtmlTextView(mActivity);
@@ -66,11 +65,11 @@ public class HelpHtmlFragment extends Fragment {
scroller.addView(text);
// load html from raw resource (Parsing handled by HtmlTextView library)
- text.setHtmlFromRawResource(getActivity(), htmlFile);
+ text.setHtmlFromRawResource(getActivity(), mHtmlFile);
// no flickering when clicking textview for Android < 4
text.setTextColor(getResources().getColor(android.R.color.black));
return scroller;
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 5ac421a44..834509f53 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -34,10 +34,8 @@ import android.support.v7.app.ActionBar;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
@@ -161,7 +159,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
} else if (extras.containsKey(EXTRA_KEY_ID)) {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, 0);
if (keyId != 0) {
- query = "0x" + PgpKeyHelper.convertKeyToHex(keyId);
+ query = PgpKeyHelper.convertKeyIdToHex(keyId);
}
} else if (extras.containsKey(EXTRA_FINGERPRINT)) {
String fingerprint = intent.getStringExtra(EXTRA_FINGERPRINT);
@@ -169,7 +167,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
query = "0x" + fingerprint;
}
} else {
- Log.e(Constants.TAG, "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or 'fingerprint' extra!");
+ Log.e(Constants.TAG,
+ "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or 'fingerprint' extra!");
return;
}
@@ -338,7 +337,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
// } else {
// status.putString(
// EXTRA_ERROR,
- // "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key.");
+ // "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key.");
// }
// }
// } catch (QueryException e) {
@@ -360,51 +359,54 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
// }
- // Message is received after importing is done in ApgService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- R.string.progress_importing, ProgressDialog.STYLE_HORIZONTAL) {
- public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
- super.handleMessage(message);
-
- if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- // get returned data bundle
- Bundle returnData = message.getData();
-
- int added = returnData.getInt(KeychainIntentService.RESULT_IMPORT_ADDED);
- int updated = returnData
- .getInt(KeychainIntentService.RESULT_IMPORT_UPDATED);
- int bad = returnData.getInt(KeychainIntentService.RESULT_IMPORT_BAD);
- String toastMessage;
- if (added > 0 && updated > 0) {
- String addedStr = getResources().getQuantityString(
- R.plurals.keys_added_and_updated_1, added, added);
- String updatedStr = getResources().getQuantityString(
- R.plurals.keys_added_and_updated_2, updated, updated);
- toastMessage = addedStr + updatedStr;
- } else if (added > 0) {
- toastMessage = getResources().getQuantityString(R.plurals.keys_added,
- added, added);
- } else if (updated > 0) {
- toastMessage = getResources().getQuantityString(R.plurals.keys_updated,
- updated, updated);
- } else {
- toastMessage = getString(R.string.no_keys_added_or_updated);
- }
- AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
- .show();
- if (bad > 0) {
- BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad);
- badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog");
- }
- }
- }
- };
-
/**
* Import keys with mImportData
*/
public void importKeys() {
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ this,
+ getString(R.string.progress_importing),
+ ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ // get returned data bundle
+ Bundle returnData = message.getData();
+
+ int added = returnData.getInt(KeychainIntentService.RESULT_IMPORT_ADDED);
+ int updated = returnData
+ .getInt(KeychainIntentService.RESULT_IMPORT_UPDATED);
+ int bad = returnData.getInt(KeychainIntentService.RESULT_IMPORT_BAD);
+ String toastMessage;
+ if (added > 0 && updated > 0) {
+ String addedStr = getResources().getQuantityString(
+ R.plurals.keys_added_and_updated_1, added, added);
+ String updatedStr = getResources().getQuantityString(
+ R.plurals.keys_added_and_updated_2, updated, updated);
+ toastMessage = addedStr + updatedStr;
+ } else if (added > 0) {
+ toastMessage = getResources().getQuantityString(R.plurals.keys_added,
+ added, added);
+ } else if (updated > 0) {
+ toastMessage = getResources().getQuantityString(R.plurals.keys_updated,
+ updated, updated);
+ } else {
+ toastMessage = getString(R.string.no_keys_added_or_updated);
+ }
+ AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
+ .show();
+ if (bad > 0) {
+ BadImportKeyDialogFragment badImportKeyDialogFragment =
+ BadImportKeyDialogFragment.newInstance(bad);
+ badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog");
+ }
+ }
+ }
+ };
+
if (mListFragment.getKeyBytes() != null || mListFragment.getDataUri() != null) {
Log.d(Constants.TAG, "importKeys started");
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java
index 211fc1f44..3f0b4a46e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java
@@ -17,17 +17,15 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
-
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
public class ImportKeysClipboardFragment extends Fragment {
@@ -60,8 +58,9 @@ public class ImportKeysClipboardFragment extends Fragment {
public void onClick(View v) {
CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
String sendText = "";
- if (clipboardText != null)
+ if (clipboardText != null) {
sendText = clipboardText.toString();
+ }
mImportActivity.loadCallback(sendText.getBytes(), null, null, null);
}
});
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
index 60b33c8a2..31d5f3fd0 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
@@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.FileHelper;
-
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
@@ -29,8 +24,11 @@ import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.FileHelper;
public class ImportKeysFileFragment extends Fragment {
private ImportKeysActivity mImportActivity;
@@ -62,7 +60,7 @@ public class ImportKeysFileFragment extends Fragment {
// open .asc or .gpg files
// setting it to text/plain prevents Cynaogenmod's file manager from selecting asc
// or gpg types!
- FileHelper.openFile(ImportKeysFileFragment.this, Constants.path.APP_DIR + "/",
+ FileHelper.openFile(ImportKeysFileFragment.this, Constants.Path.APP_DIR + "/",
"*/*", Id.request.filename);
}
});
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
index 1118f0264..9e8506193 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
@@ -17,25 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
-import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
-import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
-import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader;
-import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.util.KeyServer;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
@@ -44,8 +25,21 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.ListView;
-
import com.devspark.appmsg.AppMsg;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.ui.adapter.*;
+import org.sufficientlysecure.keychain.util.InputData;
+import org.sufficientlysecure.keychain.util.KeyServer;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
public class ImportKeysListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
@@ -184,7 +178,8 @@ public class ImportKeysListFragment extends ListFragment implements
}
@Override
- public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> onCreateLoader(int id, Bundle args) {
+ public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>>
+ onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_ID_BYTES: {
InputData inputData = getInputData(mKeyBytes, mDataUri);
@@ -219,27 +214,44 @@ public class ImportKeysListFragment extends ListFragment implements
} else {
setListShownNoAnimation(true);
}
+
+ Exception error = data.getError();
+
switch (loader.getId()) {
case LOADER_ID_BYTES:
+
+ if (error == null) {
+ // No error
+ } else if (error instanceof ImportKeysListLoader.FileHasNoContent) {
+ AppMsg.makeText(getActivity(), R.string.error_import_file_no_content,
+ AppMsg.STYLE_ALERT).show();
+ } else if (error instanceof ImportKeysListLoader.NonPgpPart) {
+ AppMsg.makeText(getActivity(),
+ ((ImportKeysListLoader.NonPgpPart) error).getCount() + " " + getResources().
+ getQuantityString(R.plurals.error_import_non_pgp_part,
+ ((ImportKeysListLoader.NonPgpPart) error).getCount()),
+ new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.confirm)).show();
+ } else {
+ AppMsg.makeText(getActivity(), R.string.error_generic_report_bug,
+ new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.alert)).show();
+ }
break;
case LOADER_ID_SERVER_QUERY:
- Exception error = data.getError();
-
- if(error == null){
+ if (error == null) {
AppMsg.makeText(
getActivity(), getResources().getQuantityString(R.plurals.keys_found,
mAdapter.getCount(), mAdapter.getCount()),
AppMsg.STYLE_INFO
).show();
- } else if(error instanceof KeyServer.InsufficientQuery){
+ } else if (error instanceof KeyServer.InsufficientQuery) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query,
AppMsg.STYLE_ALERT).show();
- }else if(error instanceof KeyServer.QueryException){
+ } else if (error instanceof KeyServer.QueryException) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_query,
AppMsg.STYLE_ALERT).show();
- }else if(error instanceof KeyServer.TooManyResponses){
+ } else if (error instanceof KeyServer.TooManyResponses) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses,
AppMsg.STYLE_ALERT).show();
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java
index 83af8cf48..110647284 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java
@@ -17,8 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.R;
-
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -26,8 +24,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.R;
public class ImportKeysNFCFragment extends Fragment {
@@ -59,7 +57,7 @@ public class ImportKeysNFCFragment extends Fragment {
public void onClick(View v) {
// show nfc help
Intent intent = new Intent(getActivity(), HelpActivity.class);
- intent.putExtra(HelpActivity.EXTRA_SELECTED_TAB, 1);
+ intent.putExtra(HelpActivity.EXTRA_SELECTED_TAB, 2);
startActivityForResult(intent, 0);
}
});
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
index ee91b2434..10c0752b1 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java
@@ -17,14 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import java.util.ArrayList;
-import java.util.Locale;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -36,9 +28,15 @@ import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
import com.google.zxing.integration.android.IntentResult;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.ArrayList;
+import java.util.Locale;
public class ImportKeysQrCodeFragment extends Fragment {
@@ -94,45 +92,45 @@ public class ImportKeysQrCodeFragment extends Fragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode & 0xFFFF) {
- case IntentIntegratorSupportV4.REQUEST_CODE: {
- IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
- resultCode, data);
- if (scanResult != null && scanResult.getFormatName() != null) {
- String scannedContent = scanResult.getContents();
-
- Log.d(Constants.TAG, "scannedContent: " + scannedContent);
-
- // look if it's fingerprint only
- if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
- importFingerprint(Uri.parse(scanResult.getContents()));
- return;
+ case IntentIntegratorSupportV4.REQUEST_CODE: {
+ IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
+ resultCode, data);
+ if (scanResult != null && scanResult.getFormatName() != null) {
+ String scannedContent = scanResult.getContents();
+
+ Log.d(Constants.TAG, "scannedContent: " + scannedContent);
+
+ // look if it's fingerprint only
+ if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
+ importFingerprint(Uri.parse(scanResult.getContents()));
+ return;
+ }
+
+ // look if it is the whole key
+ String[] parts = scannedContent.split(",");
+ if (parts.length == 3) {
+ importParts(parts);
+ return;
+ }
+
+ // is this a full key encoded as qr code?
+ if (scannedContent.startsWith("-----BEGIN PGP")) {
+ mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null);
+ return;
+ }
+
+ // fail...
+ Toast.makeText(getActivity(), R.string.import_qr_code_wrong, Toast.LENGTH_LONG)
+ .show();
}
- // look if it is the whole key
- String[] parts = scannedContent.split(",");
- if (parts.length == 3) {
- importParts(parts);
- return;
- }
-
- // is this a full key encoded as qr code?
- if (scannedContent.startsWith("-----BEGIN PGP")) {
- mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null);
- return;
- }
-
- // fail...
- Toast.makeText(getActivity(), R.string.import_qr_code_wrong, Toast.LENGTH_LONG)
- .show();
+ break;
}
- break;
- }
-
- default:
- super.onActivityResult(requestCode, resultCode, data);
+ default:
+ super.onActivityResult(requestCode, resultCode, data);
- break;
+ break;
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
index d77015aa7..0b2fff64e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java
@@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -36,8 +31,11 @@ import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.util.Log;
public class ImportKeysServerFragment extends Fragment {
public static final String ARG_QUERY = "query";
@@ -96,7 +94,8 @@ public class ImportKeysServerFragment extends Fragment {
search(query, keyServer);
// close keyboard after pressing search
- InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ InputMethodManager imm =
+ (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0);
}
});
@@ -110,7 +109,6 @@ public class ImportKeysServerFragment extends Fragment {
search(query, keyServer);
// Don't return true to let the keyboard close itself after pressing search
- // http://stackoverflow.com/questions/2342620/how-to-hide-keyboard-after-typing-in-edittext-in-android
return false;
}
return false;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
index e58ebe819..06df6f12d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * 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
@@ -17,17 +17,16 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ExportHelper;
-
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ExportHelper;
-public class KeyListSecretActivity extends DrawerActivity {
+public class KeyListActivity extends DrawerActivity {
ExportHelper mExportHelper;
@@ -37,7 +36,7 @@ public class KeyListSecretActivity extends DrawerActivity {
mExportHelper = new ExportHelper(this);
- setContentView(R.layout.key_list_secret_activity);
+ setContentView(R.layout.key_list_activity);
// now setup navigation drawer in DrawerActivity...
setupDrawerNavigation(savedInstanceState);
@@ -46,34 +45,35 @@ public class KeyListSecretActivity extends DrawerActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.key_list_secret, menu);
+ getMenuInflater().inflate(R.menu.key_list, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case R.id.menu_key_list_secret_create:
- createKey();
-
- return true;
- case R.id.menu_key_list_secret_create_expert:
- createKeyExpert();
-
- return true;
- case R.id.menu_key_list_secret_export:
- mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.path.APP_DIR
- + "/secexport.asc");
-
- return true;
- case R.id.menu_key_list_secret_import:
- Intent intentImportFromFile = new Intent(this, ImportKeysActivity.class);
- intentImportFromFile.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
- startActivityForResult(intentImportFromFile, 0);
-
- return true;
- default:
- return super.onOptionsItemSelected(item);
+ case R.id.menu_key_list_import:
+ callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS);
+
+ return true;
+ case R.id.menu_key_list_export:
+ mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null);
+
+ return true;
+ case R.id.menu_key_list_create:
+ createKey();
+
+ return true;
+ case R.id.menu_key_list_create_expert:
+ createKeyExpert();
+
+ return true;
+ case R.id.menu_key_list_secret_export:
+ mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC, null);
+
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
new file mode 100644
index 000000000..957c822d2
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -0,0 +1,686 @@
+/*
+ * 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;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.*;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.SearchView;
+import android.text.TextUtils;
+import android.view.*;
+import android.view.View.OnClickListener;
+import android.view.animation.AnimationUtils;
+import android.widget.*;
+import android.widget.AbsListView.MultiChoiceModeListener;
+import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ExportHelper;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
+import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
+import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
+import org.sufficientlysecure.keychain.util.Log;
+import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
+import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
+import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses
+ * StickyListHeaders library which does not extend upon ListView.
+ */
+public class KeyListFragment extends Fragment
+ implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener,
+ LoaderManager.LoaderCallbacks<Cursor> {
+
+ private KeyListAdapter mAdapter;
+ private StickyListHeadersListView mStickyList;
+
+ // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097
+ boolean mListShown;
+ View mProgressContainer;
+ View mListContainer;
+
+ private String mCurQuery;
+ private SearchView mSearchView;
+ // empty list layout
+ private BootstrapButton mButtonEmptyCreate;
+ private BootstrapButton mButtonEmptyImport;
+
+
+ /**
+ * Load custom layout with StickyListView from library
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.key_list_fragment, container, false);
+
+ mStickyList = (StickyListHeadersListView) root.findViewById(R.id.key_list_list);
+ mStickyList.setOnItemClickListener(this);
+
+
+ // empty view
+ mButtonEmptyCreate = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_create);
+ mButtonEmptyCreate.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(getActivity(), EditKeyActivity.class);
+ intent.setAction(EditKeyActivity.ACTION_CREATE_KEY);
+ intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true);
+ intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view
+ startActivityForResult(intent, 0);
+ }
+ });
+ mButtonEmptyImport = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_import);
+ mButtonEmptyImport.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(getActivity(), ImportKeysActivity.class);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
+ startActivityForResult(intent, 0);
+ }
+ });
+
+ // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097
+ mListContainer = root.findViewById(R.id.key_list_list_container);
+ mProgressContainer = root.findViewById(R.id.key_list_progress_container);
+ mListShown = true;
+
+ return root;
+ }
+
+ /**
+ * Define Adapter and Loader on create of Activity
+ */
+ @SuppressLint("NewApi")
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ mStickyList.setOnItemClickListener(this);
+ mStickyList.setAreHeadersSticky(true);
+ mStickyList.setDrawingListUnderStickyHeader(false);
+ mStickyList.setFastScrollEnabled(true);
+ try {
+ mStickyList.setFastScrollAlwaysVisible(true);
+ } catch (ApiLevelTooLowException e) {
+ }
+
+ // this view is made visible if no data is available
+ mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty));
+
+ /*
+ * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
+ * available for Android >= 3.0
+ */
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+ mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() {
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ android.view.MenuInflater inflater = getActivity().getMenuInflater();
+ inflater.inflate(R.menu.key_list_multi, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+
+ // get IDs for checked positions as long array
+ long[] ids;
+
+ switch (item.getItemId()) {
+ case R.id.menu_key_list_multi_encrypt: {
+ ids = mAdapter.getCurrentSelectedMasterKeyIds();
+ encrypt(mode, ids);
+ break;
+ }
+ case R.id.menu_key_list_multi_delete: {
+ ids = mStickyList.getWrappedList().getCheckedItemIds();
+ showDeleteKeyDialog(mode, ids);
+ break;
+ }
+ case R.id.menu_key_list_multi_export: {
+ ids = mStickyList.getWrappedList().getCheckedItemIds();
+ long[] masterKeyIds = new long[2*ids.length];
+ ArrayList<Long> allPubRowIds =
+ ProviderHelper.getPublicKeyRingsRowIds(getActivity());
+ for (int i = 0; i < ids.length; i++) {
+ if (allPubRowIds.contains(ids[i])) {
+ masterKeyIds[i] = ProviderHelper.getPublicMasterKeyId(getActivity(), ids[i]);
+ } else {
+ masterKeyIds[i] = ProviderHelper.getSecretMasterKeyId(getActivity(), ids[i]);
+ }
+ }
+ ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
+ mExportHelper
+ .showExportKeysDialog(masterKeyIds, Id.type.public_key,
+ Constants.Path.APP_DIR_FILE_PUB,
+ getString(R.string.also_export_secret_keys));
+ break;
+ }
+ case R.id.menu_key_list_multi_select_all: {
+ // select all
+ for (int i = 0; i < mStickyList.getCount(); i++) {
+ mStickyList.setItemChecked(i, true);
+ }
+ break;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ mAdapter.clearSelection();
+ }
+
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
+ boolean checked) {
+ if (checked) {
+ mAdapter.setNewSelection(position, checked);
+ } else {
+ mAdapter.removeSelection(position);
+ }
+ int count = mStickyList.getCheckedItemCount();
+ String keysSelected = getResources().getQuantityString(
+ R.plurals.key_list_selected_keys, count, count);
+ mode.setTitle(keysSelected);
+ }
+
+ });
+ }
+
+ // We have a menu item to show in action bar.
+ setHasOptionsMenu(true);
+
+ // NOTE: Not supported by StickyListHeader, but reimplemented here
+ // Start out with a progress indicator.
+ setListShown(false);
+
+ // Create an empty adapter we will use to display the loaded data.
+ mAdapter = new KeyListAdapter(getActivity(), null, Id.type.public_key);
+ mStickyList.setAdapter(mAdapter);
+
+ // Prepare the loader. Either re-connect with an existing one,
+ // or start a new one.
+ getLoaderManager().initLoader(0, null, this);
+ }
+
+ // These are the rows that we will retrieve.
+ static final String[] PROJECTION = new String[]{
+ KeychainContract.KeyRings._ID,
+ KeychainContract.KeyRings.TYPE,
+ KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.UserIds.USER_ID,
+ KeychainContract.Keys.IS_REVOKED
+ };
+
+ static final int INDEX_TYPE = 1;
+ static final int INDEX_MASTER_KEY_ID = 2;
+ static final int INDEX_USER_ID = 3;
+ static final int INDEX_IS_REVOKED = 4;
+
+ static final String SORT_ORDER =
+ // show secret before public key
+ KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings.TYPE + " DESC, "
+ // sort by user id otherwise
+ + UserIds.USER_ID + " ASC";
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ // This is called when a new Loader needs to be created. This
+ // sample only has one Loader, so we don't care about the ID.
+ Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
+ String where = null;
+ String whereArgs[] = null;
+ if (mCurQuery != null) {
+ where = KeychainContract.UserIds.USER_ID + " LIKE ?";
+ whereArgs = new String[]{"%" + mCurQuery + "%"};
+ }
+ // Now create and return a CursorLoader that will take care of
+ // creating a Cursor for the data being displayed.
+ return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, SORT_ORDER);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ // Swap the new cursor in. (The framework will take care of closing the
+ // old cursor once we return.)
+ mAdapter.setSearchQuery(mCurQuery);
+ mAdapter.swapCursor(data);
+
+ mStickyList.setAdapter(mAdapter);
+
+ // NOTE: Not supported by StickyListHeader, but reimplemented here
+ // The list should now be shown.
+ if (isResumed()) {
+ setListShown(true);
+ } else {
+ setListShownNoAnimation(true);
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ // This is called when the last Cursor provided to onLoadFinished()
+ // above is about to be closed. We need to make sure we are no
+ // longer using it.
+ mAdapter.swapCursor(null);
+ }
+
+ /**
+ * On click on item, start key view activity
+ */
+ @Override
+ public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
+ Intent viewIntent = null;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ viewIntent = new Intent(getActivity(), ViewKeyActivity.class);
+ } else {
+ viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
+ }
+ viewIntent.setData(
+ KeychainContract
+ .KeyRings.buildPublicKeyRingsByMasterKeyIdUri(
+ Long.toString(mAdapter.getMasterKeyId(position))));
+ startActivity(viewIntent);
+ }
+
+ @TargetApi(11)
+ protected void encrypt(ActionMode mode, long[] keyRingMasterKeyIds) {
+ Intent intent = new Intent(getActivity(), EncryptActivity.class);
+ intent.setAction(EncryptActivity.ACTION_ENCRYPT);
+ intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingMasterKeyIds);
+ // used instead of startActivity set actionbar based on callingPackage
+ startActivityForResult(intent, 0);
+
+ mode.finish();
+ }
+
+ /**
+ * Show dialog to delete key
+ *
+ * @param keyRingRowIds
+ */
+ @TargetApi(11)
+ // TODO: this method needs an overhaul to handle both public and secret keys gracefully!
+ public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
+ // Message is received after key is deleted
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
+ mode.finish();
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
+ DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
+ keyRingRowIds);
+
+ deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
+ }
+
+
+ @Override
+ public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
+ // Get the searchview
+ MenuItem searchItem = menu.findItem(R.id.menu_key_list_search);
+ mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
+
+ // Execute this when searching
+ mSearchView.setOnQueryTextListener(this);
+
+ // Erase search result without focus
+ MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ mCurQuery = null;
+ mSearchView.setQuery("", true);
+ getLoaderManager().restartLoader(0, null, KeyListFragment.this);
+ return true;
+ }
+ });
+
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ // Called when the action bar search text has changed. Update
+ // the search filter, and restart the loader to do a new query
+ // with this filter.
+ mCurQuery = !TextUtils.isEmpty(s) ? s : null;
+ getLoaderManager().restartLoader(0, null, this);
+ return true;
+ }
+
+ // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097
+ public void setListShown(boolean shown, boolean animate) {
+ if (mListShown == shown) {
+ return;
+ }
+ mListShown = shown;
+ if (shown) {
+ if (animate) {
+ mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_out));
+ mListContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_in));
+ }
+ mProgressContainer.setVisibility(View.GONE);
+ mListContainer.setVisibility(View.VISIBLE);
+ } else {
+ if (animate) {
+ mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_in));
+ mListContainer.startAnimation(AnimationUtils.loadAnimation(
+ getActivity(), android.R.anim.fade_out));
+ }
+ mProgressContainer.setVisibility(View.VISIBLE);
+ mListContainer.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097
+ public void setListShown(boolean shown) {
+ setListShown(shown, true);
+ }
+
+ // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097
+ public void setListShownNoAnimation(boolean shown) {
+ setListShown(shown, false);
+ }
+
+ /**
+ * Implements StickyListHeadersAdapter from library
+ */
+ private class KeyListAdapter extends HighlightQueryCursorAdapter implements StickyListHeadersAdapter {
+ private LayoutInflater mInflater;
+
+ private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
+
+ public KeyListAdapter(Context context, Cursor c, int flags) {
+ super(context, c, flags);
+
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public Cursor swapCursor(Cursor newCursor) {
+ return super.swapCursor(newCursor);
+ }
+
+ /**
+ * Bind cursor data to the item list view
+ * <p/>
+ * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. Thus
+ * no ViewHolder is required here.
+ */
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+
+ { // set name and stuff, common to both key types
+ TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
+ TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
+
+ String userId = cursor.getString(INDEX_USER_ID);
+ String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
+ if (userIdSplit[0] != null) {
+ mainUserId.setText(highlightSearchQuery(userIdSplit[0]));
+ } else {
+ mainUserId.setText(R.string.user_id_no_name);
+ }
+ if (userIdSplit[1] != null) {
+ mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
+ mainUserIdRest.setVisibility(View.VISIBLE);
+ } else {
+ mainUserIdRest.setVisibility(View.GONE);
+ }
+ }
+
+ { // set edit button and revoked info, specific by key type
+ View statusDivider = (View) view.findViewById(R.id.status_divider);
+ FrameLayout statusLayout = (FrameLayout) view.findViewById(R.id.status_layout);
+ Button button = (Button) view.findViewById(R.id.edit);
+ TextView revoked = (TextView) view.findViewById(R.id.revoked);
+
+ if (cursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) {
+ // this is a secret key - show the edit button
+ statusDivider.setVisibility(View.VISIBLE);
+ statusLayout.setVisibility(View.VISIBLE);
+ revoked.setVisibility(View.GONE);
+ button.setVisibility(View.VISIBLE);
+
+ final long id = cursor.getLong(INDEX_MASTER_KEY_ID);
+ button.setOnClickListener(new OnClickListener() {
+ public void onClick(View view) {
+ Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
+ editIntent.setData(
+ KeychainContract.KeyRings
+ .buildSecretKeyRingsByMasterKeyIdUri(Long.toString(id)));
+ editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
+ startActivityForResult(editIntent, 0);
+ }
+ });
+ } else {
+ // this is a public key - hide the edit button, show if it's revoked
+ statusDivider.setVisibility(View.GONE);
+ button.setVisibility(View.GONE);
+
+ boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
+ statusLayout.setVisibility(isRevoked ? View.VISIBLE : View.GONE);
+ revoked.setVisibility(isRevoked ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ }
+
+ public long getMasterKeyId(int id) {
+ if (!mCursor.moveToPosition(id)) {
+ throw new IllegalStateException("couldn't move cursor to position " + id);
+ }
+
+ return mCursor.getLong(INDEX_MASTER_KEY_ID);
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ return mInflater.inflate(R.layout.key_list_item, parent, false);
+ }
+
+ /**
+ * Creates a new header view and binds the section headers to it. It uses the ViewHolder
+ * pattern. Most functionality is similar to getView() from Android's CursorAdapter.
+ * <p/>
+ * NOTE: The variables mDataValid and mCursor are available due to the super class
+ * CursorAdapter.
+ */
+ @Override
+ public View getHeaderView(int position, View convertView, ViewGroup parent) {
+ HeaderViewHolder holder;
+ if (convertView == null) {
+ holder = new HeaderViewHolder();
+ convertView = mInflater.inflate(R.layout.key_list_header, parent, false);
+ holder.mText = (TextView) convertView.findViewById(R.id.stickylist_header_text);
+ holder.mCount = (TextView) convertView.findViewById(R.id.contacts_num);
+ convertView.setTag(holder);
+ } else {
+ holder = (HeaderViewHolder) convertView.getTag();
+ }
+
+ if (!mDataValid) {
+ // no data available at this point
+ Log.d(Constants.TAG, "getHeaderView: No data available at this point!");
+ return convertView;
+ }
+
+ if (!mCursor.moveToPosition(position)) {
+ throw new IllegalStateException("couldn't move cursor to position " + position);
+ }
+
+ if (mCursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) {
+ { // set contact count
+ int num = mCursor.getCount();
+ String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num);
+ holder.mCount.setText(contactsTotal);
+ holder.mCount.setVisibility(View.VISIBLE);
+ }
+
+ holder.mText.setText(convertView.getResources().getString(R.string.my_keys));
+ return convertView;
+ }
+
+ // set header text as first char in user id
+ String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
+ String headerText = convertView.getResources().getString(R.string.user_id_no_name);
+ if (userId != null && userId.length() > 0) {
+ headerText = "" +
+ mCursor.getString(KeyListFragment.INDEX_USER_ID).subSequence(0, 1).charAt(0);
+ }
+ holder.mText.setText(headerText);
+ holder.mCount.setVisibility(View.GONE);
+ return convertView;
+ }
+
+ /**
+ * Header IDs should be static, position=1 should always return the same Id that is.
+ */
+ @Override
+ public long getHeaderId(int position) {
+ if (!mDataValid) {
+ // no data available at this point
+ Log.d(Constants.TAG, "getHeaderView: No data available at this point!");
+ return -1;
+ }
+
+ if (!mCursor.moveToPosition(position)) {
+ throw new IllegalStateException("couldn't move cursor to position " + position);
+ }
+
+ // early breakout: all secret keys are assigned id 0
+ if (mCursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) {
+ return 1L;
+ }
+ // otherwise, return the first character of the name as ID
+ String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
+ if (userId != null && userId.length() > 0) {
+ return userId.charAt(0);
+ } else {
+ return Long.MAX_VALUE;
+ }
+ }
+
+ class HeaderViewHolder {
+ TextView mText;
+ TextView mCount;
+ }
+
+ /**
+ * -------------------------- MULTI-SELECTION METHODS --------------
+ */
+ public void setNewSelection(int position, boolean value) {
+ mSelection.put(position, value);
+ notifyDataSetChanged();
+ }
+
+ public long[] getCurrentSelectedMasterKeyIds() {
+ long[] ids = new long[mSelection.size()];
+ int i = 0;
+ // get master key ids
+ for (int pos : mSelection.keySet()) {
+ ids[i++] = mAdapter.getMasterKeyId(pos);
+ }
+ return ids;
+ }
+
+ public void removeSelection(int position) {
+ mSelection.remove(position);
+ notifyDataSetChanged();
+ }
+
+ public void clearSelection() {
+ mSelection.clear();
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // let the adapter handle setting up the row views
+ View v = super.getView(position, convertView, parent);
+
+ /**
+ * Change color for multi-selection
+ */
+ if (mSelection.get(position) != null) {
+ // selected position color
+ v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
+ } else {
+ // default color
+ v.setBackgroundColor(Color.TRANSPARENT);
+ }
+
+ return v;
+ }
+
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java
deleted file mode 100644
index 4521786f7..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicActivity.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ExportHelper;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-
-public class KeyListPublicActivity extends DrawerActivity {
-
- ExportHelper mExportHelper;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mExportHelper = new ExportHelper(this);
-
- setContentView(R.layout.key_list_public_activity);
-
- // now setup navigation drawer in DrawerActivity...
- setupDrawerNavigation(savedInstanceState);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.key_list_public, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_key_list_public_import:
- Intent intentImport = new Intent(this, ImportKeysActivity.class);
- startActivityForResult(intentImport, 0);
-
- return true;
- case R.id.menu_key_list_public_export:
- mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR
- + "/pubexport.asc");
-
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
deleted file mode 100644
index f2cb8a265..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2013 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 java.util.Set;
-
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.ui.adapter.KeyListPublicAdapter;
-import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
-
-import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
-import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Intent;
-import android.database.Cursor;
-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.Fragment;
-import android.support.v4.app.LoaderManager;
-import android.support.v4.content.CursorLoader;
-import android.support.v4.content.Loader;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
-import android.text.TextUtils;
-import android.view.ActionMode;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AbsListView.MultiChoiceModeListener;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.Toast;
-
-import com.beardedhen.androidbootstrap.BootstrapButton;
-
-/**
- * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses
- * StickyListHeaders library which does not extend upon ListView.
- */
-public class KeyListPublicFragment extends Fragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener,
- LoaderManager.LoaderCallbacks<Cursor> {
-
- private KeyListPublicAdapter mAdapter;
- private StickyListHeadersListView mStickyList;
- private String mCurQuery;
- private SearchView mSearchView;
- // empty list layout
- private BootstrapButton mButtonEmptyCreate;
- private BootstrapButton mButtonEmptyImport;
-
-
- /**
- * Load custom layout with StickyListView from library
- */
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.key_list_public_fragment, container, false);
- setHasOptionsMenu(true);
- mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create);
- mButtonEmptyCreate.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(getActivity(), EditKeyActivity.class);
- intent.setAction(EditKeyActivity.ACTION_CREATE_KEY);
- intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true);
- intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view
- startActivityForResult(intent, 0);
- }
- });
-
- mButtonEmptyImport = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_import);
- mButtonEmptyImport.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(getActivity(), ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
- startActivityForResult(intent, 0);
- }
- });
-
- return view;
- }
-
- /**
- * Define Adapter and Loader on create of Activity
- */
- @SuppressLint("NewApi")
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list);
-
- mStickyList.setOnItemClickListener(this);
- mStickyList.setAreHeadersSticky(true);
- mStickyList.setDrawingListUnderStickyHeader(false);
- mStickyList.setFastScrollEnabled(true);
- try {
- mStickyList.setFastScrollAlwaysVisible(true);
- } catch (ApiLevelTooLowException e) {
- }
-
- // this view is made visible if no data is available
- mStickyList.setEmptyView(getActivity().findViewById(R.id.empty));
-
- /*
- * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
- * available for Android >= 3.0
- */
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
- mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() {
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- android.view.MenuInflater inflater = getActivity().getMenuInflater();
- inflater.inflate(R.menu.key_list_public_multi, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return false;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- Set<Integer> positions = mAdapter.getCurrentCheckedPosition();
-
- // get IDs for checked positions as long array
- long[] ids = new long[positions.size()];
- int i = 0;
- for (int pos : positions) {
- ids[i] = mAdapter.getItemId(pos);
- i++;
- }
-
- switch (item.getItemId()) {
- case R.id.menu_key_list_public_multi_encrypt: {
- encrypt(mode, ids);
- break;
- }
- case R.id.menu_key_list_public_multi_delete: {
- showDeleteKeyDialog(mode, ids);
- break;
- }
- case R.id.menu_key_list_public_multi_select_all: {
- //Select all
- int localCount = mStickyList.getCount();
- for(int k = 0; k < localCount; k++) {
- mStickyList.setItemChecked(k, true);
- }
- break;
- }
- }
- return true;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- mAdapter.clearSelection();
- }
-
- @Override
- public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
- if (checked) {
- mAdapter.setNewSelection(position, checked);
- } else {
- mAdapter.removeSelection(position);
- }
- int count = mAdapter.getCurrentCheckedPosition().size();
- String keysSelected = getResources().getQuantityString(
- R.plurals.key_list_selected_keys, count, count);
- mode.setTitle(keysSelected);
- }
-
- });
- }
-
- // NOTE: Not supported by StickyListHeader, thus no indicator is shown while loading
- // Start out with a progress indicator.
- // setListShown(false);
-
- // Create an empty adapter we will use to display the loaded data.
- mAdapter = new KeyListPublicAdapter(getActivity(), null, Id.type.public_key, USER_ID_INDEX);
- mStickyList.setAdapter(mAdapter);
-
- // Prepare the loader. Either re-connect with an existing one,
- // or start a new one.
- getLoaderManager().initLoader(0, null, this);
- }
-
- // These are the rows that we will retrieve.
- static final String[] PROJECTION = new String[]{
- KeychainContract.KeyRings._ID,
- KeychainContract.KeyRings.MASTER_KEY_ID,
- KeychainContract.UserIds.USER_ID,
- KeychainContract.Keys.IS_REVOKED
- };
-
- static final int USER_ID_INDEX = 2;
-
- static final String SORT_ORDER = UserIds.USER_ID + " ASC";
-
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- // This is called when a new Loader needs to be created. This
- // sample only has one Loader, so we don't care about the ID.
- Uri baseUri = KeyRings.buildPublicKeyRingsUri();
- String where = null;
- String whereArgs[] = null;
- if(mCurQuery != null){
- where = KeychainContract.UserIds.USER_ID + " LIKE ?";
- whereArgs = new String[]{mCurQuery+"%"};
- }
- // Now create and return a CursorLoader that will take care of
- // creating a Cursor for the data being displayed.
- return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, SORT_ORDER);
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- // Swap the new cursor in. (The framework will take care of closing the
- // old cursor once we return.)
- mAdapter.swapCursor(data);
-
- mStickyList.setAdapter(mAdapter);
-
- // NOTE: Not supported by StickyListHeader, thus no indicator is shown while loading
- // The list should now be shown.
- // if (isResumed()) {
- // setListShown(true);
- // } else {
- // setListShownNoAnimation(true);
- // }
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
- // This is called when the last Cursor provided to onLoadFinished()
- // above is about to be closed. We need to make sure we are no
- // longer using it.
- mAdapter.swapCursor(null);
- }
-
- /**
- * On click on item, start key view activity
- */
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
- Intent viewIntent = null;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
- viewIntent = new Intent(getActivity(), ViewKeyActivity.class);
- } else {
- viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
- }
- viewIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id)));
- startActivity(viewIntent);
- }
-
- @TargetApi(11)
- public void encrypt(ActionMode mode, long[] keyRingRowIds) {
- // get master key ids from row ids
- long[] keyRingIds = new long[keyRingRowIds.length];
- for (int i = 0; i < keyRingRowIds.length; i++) {
- keyRingIds[i] = ProviderHelper.getPublicMasterKeyId(getActivity(), keyRingRowIds[i]);
- }
-
- Intent intent = new Intent(getActivity(), EncryptActivity.class);
- intent.setAction(EncryptActivity.ACTION_ENCRYPT);
- intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingIds);
- // used instead of startActivity set actionbar based on callingPackage
- startActivityForResult(intent, 0);
-
- mode.finish();
- }
-
- /**
- * Show dialog to delete key
- *
- * @param keyRingRowIds
- */
- @TargetApi(11)
- public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
- // Message is received after key is deleted
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
- Bundle returnData = message.getData();
- if (returnData != null
- && returnData.containsKey(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED)) {
- ArrayList<String> notDeleted =
- returnData.getStringArrayList(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED);
- String notDeletedMsg = "";
- for (String userId : notDeleted) {
- notDeletedMsg += userId + "\n";
- }
- Toast.makeText(getActivity(), getString(R.string.error_can_not_delete_contacts, notDeletedMsg)
- + getResources().getQuantityString(R.plurals.error_can_not_delete_info, notDeleted.size()),
- Toast.LENGTH_LONG).show();
-
- mode.finish();
- }
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
- keyRingRowIds, Id.type.public_key);
-
- deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
- }
-
-
- @Override
- public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
-
- // Get the searchview
- MenuItem searchItem = menu.findItem(R.id.menu_key_list_public_search);
- mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
-
- // Execute this when searching
- mSearchView.setOnQueryTextListener(this);
-
- super.onCreateOptionsMenu(menu, inflater);
-
- }
-
- @Override
- public boolean onQueryTextSubmit(String s) {
- return true;
- }
-
- @Override
- public boolean onQueryTextChange(String s) {
- // Called when the action bar search text has changed. Update
- // the search filter, and restart the loader to do a new query
- // with this filter.
- String newQuery = !TextUtils.isEmpty(s) ? s : null;
- mCurQuery = newQuery;
- getLoaderManager().restartLoader(0, null, this);
- return true;
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java
deleted file mode 100644
index eaac6d8b1..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2013 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 java.util.Set;
-
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-import org.sufficientlysecure.keychain.ui.adapter.KeyListSecretAdapter;
-import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
-
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.Intent;
-import android.database.Cursor;
-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.ListFragment;
-import android.support.v4.app.LoaderManager;
-import android.support.v4.content.CursorLoader;
-import android.support.v4.content.Loader;
-import android.view.ActionMode;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.AbsListView.MultiChoiceModeListener;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.Toast;
-
-public class KeyListSecretFragment extends ListFragment implements
- LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener {
-
- private KeyListSecretActivity mKeyListSecretActivity;
- private KeyListSecretAdapter mAdapter;
-
- /**
- * Define Adapter and Loader on create of Activity
- */
- @SuppressLint("NewApi")
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- mKeyListSecretActivity = (KeyListSecretActivity) getActivity();
-
- getListView().setOnItemClickListener(this);
-
- // Give some text to display if there is no data. In a real
- // application this would come from a resource.
- setEmptyText(getString(R.string.list_empty));
-
- /*
- * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
- * available for Android >= 3.0
- */
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
- getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- android.view.MenuInflater inflater = getActivity().getMenuInflater();
- inflater.inflate(R.menu.key_list_secret_multi, menu);
- return true;
- }
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return false;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- Set<Integer> positions = mAdapter.getCurrentCheckedPosition();
-
- // get IDs for checked positions as long array
- long[] ids = new long[positions.size()];
- int i = 0;
- for (int pos : positions) {
- ids[i] = mAdapter.getItemId(pos);
- i++;
- }
-
- switch (item.getItemId()) {
- case R.id.menu_key_list_public_multi_delete: {
- showDeleteKeyDialog(mode, ids);
- break;
- }
- case R.id.menu_key_list_public_multi_select_all: {
- //Select all
- int localCount = getListView().getCount();
- for(int k = 0; k < localCount; k++) {
- getListView().setItemChecked(k, true);
- }
- break;
- }
- }
- return true;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- mAdapter.clearSelection();
- }
-
- @Override
- public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
- if (checked) {
- mAdapter.setNewSelection(position, checked);
- } else {
- mAdapter.removeSelection(position);
- }
-
- int count = getListView().getCheckedItemCount();
- String keysSelected = getResources().getQuantityString(
- R.plurals.key_list_selected_keys, count, count);
- mode.setTitle(keysSelected);
- }
-
- });
- }
-
- // We have a menu item to show in action bar.
- setHasOptionsMenu(true);
-
- // Start out with a progress indicator.
- setListShown(false);
-
- // Create an empty adapter we will use to display the loaded data.
- mAdapter = new KeyListSecretAdapter(mKeyListSecretActivity, null, 0);
- setListAdapter(mAdapter);
-
- // Prepare the loader. Either re-connect with an existing one,
- // or start a new one.
- getLoaderManager().initLoader(0, null, this);
- }
-
- // These are the rows that we will retrieve.
- static final String[] PROJECTION = new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID,
- UserIds.USER_ID};
- static final String SORT_ORDER = UserIds.USER_ID + " COLLATE LOCALIZED ASC";
-
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- // This is called when a new Loader needs to be created. This
- // sample only has one Loader, so we don't care about the ID.
- // First, pick the base URI to use depending on whether we are
- // currently filtering.
- Uri baseUri = KeyRings.buildSecretKeyRingsUri();
-
- // Now create and return a CursorLoader that will take care of
- // creating a Cursor for the data being displayed.
- return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, SORT_ORDER);
- }
-
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- // Swap the new cursor in. (The framework will take care of closing the
- // old cursor once we return.)
- mAdapter.swapCursor(data);
-
- // The list should now be shown.
- if (isResumed()) {
- setListShown(true);
- } else {
- setListShownNoAnimation(true);
- }
- }
-
- public void onLoaderReset(Loader<Cursor> loader) {
- // This is called when the last Cursor provided to onLoadFinished()
- // above is about to be closed. We need to make sure we are no
- // longer using it.
- mAdapter.swapCursor(null);
- }
-
- /**
- * On click on item, start key view activity
- */
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
- Intent editIntent = new Intent(mKeyListSecretActivity, EditKeyActivity.class);
- editIntent.setData(KeychainContract.KeyRings.buildSecretKeyRingsUri(Long.toString(id)));
- editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
- startActivityForResult(editIntent, 0);
- }
-
- /**
- * Show dialog to delete key
- *
- * @param keyRingRowIds
- */
- @TargetApi(11)
- public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
- // Message is received after key is deleted
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
- mode.finish();
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
- keyRingRowIds, Id.type.secret_key);
-
- deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
index af20b499b..04179cb80 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
@@ -16,6 +16,11 @@
package org.sufficientlysecure.keychain.ui;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.*;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
@@ -24,25 +29,13 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.support.v7.app.ActionBarActivity;
-
import java.util.List;
@SuppressLint("NewApi")
public class PreferencesActivity extends PreferenceActivity {
- public final static String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN";
- public final static String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
+ public static final String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN";
+ public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
private PreferenceScreen mKeyServerPreference = null;
private static Preferences mPreferences;
@@ -57,16 +50,15 @@ public class PreferencesActivity extends PreferenceActivity {
// actionBar.setDisplayHomeAsUpEnabled(false);
// actionBar.setHomeButtonEnabled(false);
- //addPreferencesFromResource(R.xml.preferences);
String action = getIntent().getAction();
if (action != null && action.equals(ACTION_PREFS_GEN)) {
addPreferencesFromResource(R.xml.gen_preferences);
initializePassPassPhraceCacheTtl(
- (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL));
+ (IntegerListPreference) findPreference(Constants.Pref.PASS_PHRASE_CACHE_TTL));
- mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS);
+ mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
String servers[] = mPreferences.getKeyServers();
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
servers.length, servers.length));
@@ -86,11 +78,11 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.adv_preferences);
initializeEncryptionAlgorithm(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM));
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM));
- int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip,
+ int[] valueIds = new int[]{Id.choice.compression.none, Id.choice.compression.zip,
Id.choice.compression.zlib, Id.choice.compression.bzip2, };
- String[] entries = new String[] {
+ String[] entries = new String[]{
getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
"ZIP (" + getString(R.string.compression_fast) + ")",
"ZLIB (" + getString(R.string.compression_fast) + ")",
@@ -101,20 +93,22 @@ public class PreferencesActivity extends PreferenceActivity {
}
initializeHashAlgorithm(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM),
- valueIds, entries, values);
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM),
+ valueIds, entries, values);
initializeMessageCompression(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION),
- valueIds, entries, values);
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
+ valueIds, entries, values);
initializeFileCompression(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION),
- entries, values);
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
+ entries, values);
- initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR));
+ initializeAsciiArmour(
+ (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOUR));
- initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES));
+ initializeForceV3Signatures(
+ (CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Load the legacy preferences headers
@@ -151,7 +145,9 @@ public class PreferencesActivity extends PreferenceActivity {
loadHeadersFromResource(R.xml.preference_headers, target);
}
- /** This fragment shows the general preferences in android 3.0+ */
+ /**
+ * This fragment shows the general preferences in android 3.0+
+ */
public static class GeneralPrefsFragment extends PreferenceFragment {
private PreferenceScreen mKeyServerPreference = null;
@@ -164,9 +160,9 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.gen_preferences);
initializePassPassPhraceCacheTtl(
- (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL));
+ (IntegerListPreference) findPreference(Constants.Pref.PASS_PHRASE_CACHE_TTL));
- mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS);
+ mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
String servers[] = mPreferences.getKeyServers();
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
servers.length, servers.length));
@@ -206,7 +202,9 @@ public class PreferencesActivity extends PreferenceActivity {
}
}
- /** This fragment shows the advanced preferences in android 3.0+ */
+ /**
+ * This fragment shows the advanced preferences in android 3.0+
+ */
public static class AdvancedPrefsFragment extends PreferenceFragment {
@Override
@@ -217,11 +215,11 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.adv_preferences);
initializeEncryptionAlgorithm(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM));
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM));
- int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip,
+ int[] valueIds = new int[]{Id.choice.compression.none, Id.choice.compression.zip,
Id.choice.compression.zlib, Id.choice.compression.bzip2, };
- String[] entries = new String[] {
+ String[] entries = new String[]{
getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
"ZIP (" + getString(R.string.compression_fast) + ")",
"ZLIB (" + getString(R.string.compression_fast) + ")",
@@ -232,24 +230,26 @@ public class PreferencesActivity extends PreferenceActivity {
}
initializeHashAlgorithm(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM),
- valueIds, entries, values);
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM),
+ valueIds, entries, values);
initializeMessageCompression(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION),
- valueIds, entries, values);
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
+ valueIds, entries, values);
initializeFileCompression(
- (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION),
+ (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
entries, values);
- initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR));
+ initializeAsciiArmour(
+ (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOUR));
- initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES));
+ initializeForceV3Signatures(
+ (CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
}
}
- protected boolean isValidFragment (String fragmentName) {
+ protected boolean isValidFragment(String fragmentName) {
return AdvancedPrefsFragment.class.getName().equals(fragmentName)
|| GeneralPrefsFragment.class.getName().equals(fragmentName)
|| super.isValidFragment(fragmentName);
@@ -270,11 +270,11 @@ public class PreferencesActivity extends PreferenceActivity {
}
private static void initializeEncryptionAlgorithm(final IntegerListPreference mEncryptionAlgorithm) {
- int valueIds[] = { PGPEncryptedData.AES_128, PGPEncryptedData.AES_192,
+ int valueIds[] = {PGPEncryptedData.AES_128, PGPEncryptedData.AES_192,
PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH,
PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES,
PGPEncryptedData.IDEA, };
- String entries[] = { "AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5",
+ String entries[] = {"AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5",
"DES", "Triple DES", "IDEA", };
String values[] = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
@@ -298,10 +298,10 @@ public class PreferencesActivity extends PreferenceActivity {
private static void initializeHashAlgorithm
(final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) {
- valueIds = new int[] { HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160,
+ valueIds = new int[]{HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160,
HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256,
HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, };
- entries = new String[] { "MD5", "RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
+ entries = new String[]{"MD5", "RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
"SHA-512", };
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
@@ -321,8 +321,9 @@ public class PreferencesActivity extends PreferenceActivity {
});
}
- private static void initializeMessageCompression
- (final IntegerListPreference mMessageCompression, int[] valueIds, String[] entries, String[] values) {
+ private static void initializeMessageCompression(
+ final IntegerListPreference mMessageCompression,
+ int[] valueIds, String[] entries, String[] values) {
mMessageCompression.setEntries(entries);
mMessageCompression.setEntryValues(values);
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
@@ -377,4 +378,4 @@ public class PreferencesActivity extends PreferenceActivity {
}
});
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java
index b39b93f52..719378274 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java
@@ -16,14 +16,6 @@
package org.sufficientlysecure.keychain.ui;
-import java.util.Vector;
-
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ActionBarHelper;
-import org.sufficientlysecure.keychain.ui.widget.Editor;
-import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
-import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor;
-
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -33,6 +25,13 @@ 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.helper.ActionBarHelper;
+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 PreferencesKeyServerActivity extends ActionBarActivity implements OnClickListener,
EditorListener {
@@ -50,20 +49,21 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
super.onCreate(savedInstanceState);
// Inflate a "Done"/"Cancel" custom action bar view
- ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay,
+ ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
// ok
okClicked();
}
- }, R.string.btn_do_not_save, new View.OnClickListener() {
+ }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel
cancelClicked();
}
- });
+ }
+ );
setContentView(R.layout.key_server_preference);
@@ -81,11 +81,11 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
Intent intent = getIntent();
String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS);
if (servers != null) {
- for (int i = 0; i < servers.length; ++i) {
+ for (String serv : servers) {
KeyServerEditor view = (KeyServerEditor) mInflater.inflate(
R.layout.key_server_editor, mEditors, false);
view.setEditorListener(this);
- view.setValue(servers[i]);
+ view.setValue(serv);
mEditors.addView(view);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java
index 86ae0073f..874703704 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java
@@ -17,14 +17,13 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ActionBarHelper;
-
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ActionBarHelper;
public class SelectPublicKeyActivity extends ActionBarActivity {
@@ -39,27 +38,28 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
SelectPublicKeyFragment mSelectFragment;
- long selectedMasterKeyIds[];
+ long mSelectedMasterKeyIds[];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate a "Done"/"Cancel" custom action bar view
- ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay,
+ ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
// ok
okClicked();
}
- }, R.string.btn_do_not_save, new View.OnClickListener() {
+ }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel
cancelClicked();
}
- });
+ }
+ );
setContentView(R.layout.select_public_key_activity);
@@ -79,7 +79,7 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
}
// Create an instance of the fragment
- mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds);
+ mSelectFragment = SelectPublicKeyFragment.newInstance(mSelectedMasterKeyIds);
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
@@ -124,7 +124,7 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
// }
// preselected master keys
- selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
+ mSelectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
}
private void cancelClicked() {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java
index a43c84cf4..6ab9f1c6e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java
@@ -17,20 +17,7 @@
package org.sufficientlysecure.keychain.ui;
-import java.util.Date;
-import java.util.Vector;
-
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
-import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
-
-import android.app.Activity;
+import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
@@ -41,20 +28,40 @@ import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
-import android.widget.EditText;
-import android.widget.ListView;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
+import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
+import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
+
+import java.util.Date;
+import java.util.Vector;
public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher,
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids";
- private Activity mActivity;
private SelectKeyCursorAdapter mAdapter;
- private ListView mListView;
private EditText mSearchView;
private long mSelectedMasterKeyIds[];
private String mCurQuery;
+ // copied from ListFragment
+ static final int INTERNAL_EMPTY_ID = 0x00ff0001;
+ static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002;
+ static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;
+ // added for search view
+ static final int SEARCH_ID = 0x00ff0004;
+
/**
* Creates new instance of this fragment
*/
@@ -72,27 +79,101 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mSearchView = (EditText)getActivity().findViewById(R.id.select_public_key_search);
- mSearchView.addTextChangedListener(this);
mSelectedMasterKeyIds = getArguments().getLongArray(ARG_PRESELECTED_KEY_IDS);
}
/**
+ * Copied from ListFragment and added EditText for search on top of list.
+ * We do not use a custom layout here, because this breaks the progress bar functionality
+ * of ListFragment.
+ *
+ * @param inflater
+ * @param container
+ * @param savedInstanceState
+ * @return
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ final Context context = getActivity();
+
+ FrameLayout root = new FrameLayout(context);
+
+ // ------------------------------------------------------------------
+
+ LinearLayout pframe = new LinearLayout(context);
+ pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);
+ pframe.setOrientation(LinearLayout.VERTICAL);
+ pframe.setVisibility(View.GONE);
+ pframe.setGravity(Gravity.CENTER);
+
+ ProgressBar progress = new ProgressBar(context, null,
+ android.R.attr.progressBarStyleLarge);
+ pframe.addView(progress, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ root.addView(pframe, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+ // ------------------------------------------------------------------
+
+ FrameLayout lframe = new FrameLayout(context);
+ lframe.setId(INTERNAL_LIST_CONTAINER_ID);
+
+ TextView tv = new TextView(getActivity());
+ tv.setId(INTERNAL_EMPTY_ID);
+ tv.setGravity(Gravity.CENTER);
+ lframe.addView(tv, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+ // Added for search view: linearLayout, mSearchView
+ LinearLayout linearLayout = new LinearLayout(context);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ mSearchView = new EditText(context);
+ mSearchView.setId(SEARCH_ID);
+ mSearchView.setHint(R.string.menu_search);
+ mSearchView.setCompoundDrawablesWithIntrinsicBounds(
+ getResources().getDrawable(R.drawable.ic_action_search), null, null, null);
+
+ linearLayout.addView(mSearchView, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ ListView lv = new ListView(getActivity());
+ lv.setId(android.R.id.list);
+ lv.setDrawSelectorOnTop(false);
+ linearLayout.addView(lv, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+ lframe.addView(linearLayout, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+ root.addView(lframe, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+ // ------------------------------------------------------------------
+
+ root.setLayoutParams(new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+ return root;
+ }
+
+ /**
* Define Adapter and Loader on create of Activity
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- mActivity = getActivity();
- mListView = getListView();
+ getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
setEmptyText(getString(R.string.list_empty));
- mAdapter = new SelectKeyCursorAdapter(mActivity, null, 0, mListView, Id.type.public_key);
+ mSearchView.addTextChangedListener(this);
+
+ mAdapter = new SelectKeyCursorAdapter(getActivity(), null, 0, getListView(), Id.type.public_key);
setListAdapter(mAdapter);
@@ -106,16 +187,16 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
/**
* Selects items based on master key ids in list view
- *
+ *
* @param masterKeyIds
*/
private void preselectMasterKeyIds(long[] masterKeyIds) {
if (masterKeyIds != null) {
- for (int i = 0; i < mListView.getCount(); ++i) {
+ for (int i = 0; i < getListView().getCount(); ++i) {
long keyId = mAdapter.getMasterKeyId(i);
- for (int j = 0; j < masterKeyIds.length; ++j) {
- if (keyId == masterKeyIds[j]) {
- mListView.setItemChecked(i, true);
+ for (long masterKeyId : masterKeyIds) {
+ if (keyId == masterKeyId) {
+ getListView().setItemChecked(i, true);
break;
}
}
@@ -125,15 +206,15 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
/**
* Returns all selected master key ids
- *
+ *
* @return
*/
public long[] getSelectedMasterKeyIds() {
// mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key
// ids!
Vector<Long> vector = new Vector<Long>();
- for (int i = 0; i < mListView.getCount(); ++i) {
- if (mListView.isItemChecked(i)) {
+ for (int i = 0; i < getListView().getCount(); ++i) {
+ if (getListView().isItemChecked(i)) {
vector.add(mAdapter.getMasterKeyId(i));
}
}
@@ -149,13 +230,13 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
/**
* Returns all selected user ids
- *
+ *
* @return
*/
public String[] getSelectedUserIds() {
Vector<String> userIds = new Vector<String>();
- for (int i = 0; i < mListView.getCount(); ++i) {
- if (mListView.isItemChecked(i)) {
+ for (int i = 0; i < getListView().getCount(); ++i) {
+ if (getListView().isItemChecked(i)) {
userIds.add((String) mAdapter.getUserId(i));
}
}
@@ -173,7 +254,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
// These are the rows that we will retrieve.
long now = new Date().getTime() / 1000;
- String[] projection = new String[] {
+ String[] projection = new String[]{
KeyRings._ID,
KeyRings.MASTER_KEY_ID,
UserIds.USER_ID,
@@ -204,22 +285,6 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
inMasterKeyList += ")";
}
- // if (searchString != null && searchString.trim().length() > 0) {
- // String[] chunks = searchString.trim().split(" +");
- // qb.appendWhere("(EXISTS (SELECT tmp." + UserIds._ID + " FROM " + UserIds.TABLE_NAME
- // + " AS tmp WHERE " + "tmp." + UserIds.KEY_ID + " = " + Keys.TABLE_NAME + "."
- // + Keys._ID);
- // for (int i = 0; i < chunks.length; ++i) {
- // qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE ");
- // qb.appendWhereEscapeString("%" + chunks[i] + "%");
- // }
- // qb.appendWhere("))");
- //
- // if (inIdList != null) {
- // qb.appendWhere(" OR (" + inIdList + ")");
- // }
- // }
-
String orderBy = UserIds.USER_ID + " ASC";
if (inMasterKeyList != null) {
// sort by selected master keys
@@ -227,9 +292,9 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
}
String where = null;
String whereArgs[] = null;
- if(mCurQuery != null){
+ if (mCurQuery != null) {
where = UserIds.USER_ID + " LIKE ?";
- whereArgs = new String[]{mCurQuery+"%"};
+ whereArgs = new String[]{"%" + mCurQuery + "%"};
}
// Now create and return a CursorLoader that will take care of
@@ -241,6 +306,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
+ mAdapter.setSearchQuery(mCurQuery);
mAdapter.swapCursor(data);
// The list should now be shown.
@@ -274,8 +340,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
@Override
public void afterTextChanged(Editable editable) {
- String newQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null;
- mCurQuery = newQuery;
+ mCurQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null;
getLoaderManager().restartLoader(0, null, this);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java
index cd3b2cf78..0ff88d97c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java
@@ -1,43 +1,37 @@
/*
- * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
- * 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
+ * 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.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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.
*
- * 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.
+ * 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 org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
-import android.view.Menu;
-public class SelectSecretKeyActivity extends ActionBarActivity {
+import org.sufficientlysecure.keychain.R;
- // Actions for internal use only:
- public static final String ACTION_SELECT_SECRET_KEY = Constants.INTENT_PREFIX
- + "SELECT_SECRET_KEYRING";
+public class SelectSecretKeyActivity extends ActionBarActivity {
public static final String EXTRA_FILTER_CERTIFY = "filter_certify";
public static final String RESULT_EXTRA_MASTER_KEY_ID = "master_key_id";
- public static final String RESULT_EXTRA_USER_ID = "user_id";
- private boolean mFilterCertify = false;
+ private boolean mFilterCertify;
private SelectSecretKeyFragment mSelectFragment;
@Override
@@ -51,23 +45,8 @@ public class SelectSecretKeyActivity extends ActionBarActivity {
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setHomeButtonEnabled(false);
- setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
-
- // TODO: reimplement!
- // mFilterLayout = findViewById(R.id.layout_filter);
- // mFilterInfo = (TextView) mFilterLayout.findViewById(R.id.filterInfo);
- // mClearFilterButton = (Button) mFilterLayout.findViewById(R.id.btn_clear);
- //
- // mClearFilterButton.setOnClickListener(new OnClickListener() {
- // public void onClick(View v) {
- // handleIntent(new Intent());
- // }
- // });
-
mFilterCertify = getIntent().getBooleanExtra(EXTRA_FILTER_CERTIFY, false);
- handleIntent(getIntent());
-
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.select_secret_key_fragment_container) != null) {
@@ -90,49 +69,15 @@ public class SelectSecretKeyActivity extends ActionBarActivity {
/**
* This is executed by SelectSecretKeyFragment after clicking on an item
- *
- * @param masterKeyId
- * @param userId
+ *
+ * @param selectedUri
*/
- public void afterListSelection(long masterKeyId, String userId) {
+ public void afterListSelection(Uri selectedUri) {
Intent data = new Intent();
- data.putExtra(RESULT_EXTRA_MASTER_KEY_ID, masterKeyId);
- data.putExtra(RESULT_EXTRA_USER_ID, (String) userId);
+ data.setData(selectedUri);
+
setResult(RESULT_OK, data);
finish();
}
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- handleIntent(intent);
- }
-
- private void handleIntent(Intent intent) {
- // TODO: reimplement!
-
- // String searchString = null;
- // if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- // searchString = intent.getStringExtra(SearchManager.QUERY);
- // if (searchString != null && searchString.trim().length() == 0) {
- // searchString = null;
- // }
- // }
-
- // if (searchString == null) {
- // mFilterLayout.setVisibility(View.GONE);
- // } else {
- // mFilterLayout.setVisibility(View.VISIBLE);
- // mFilterInfo.setText(getString(R.string.filterInfo, searchString));
- // }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // TODO: reimplement!
- // menu.add(0, Id.menu.option.search, 0, R.string.menu_search).setIcon(
- // android.R.drawable.ic_menu_search);
- return true;
- }
-
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java
index 8ee2d381e..2efa7d33a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import java.util.Date;
-
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
-import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
-
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -40,15 +29,26 @@ import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
+import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
+import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
+
+import java.util.Date;
+
public class SelectSecretKeyFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
private SelectSecretKeyActivity mActivity;
private SelectKeyCursorAdapter mAdapter;
private ListView mListView;
-
+
private boolean mFilterCertify;
-
+
private static final String ARG_FILTER_CERTIFY = "filter_certify";
/**
@@ -56,10 +56,9 @@ public class SelectSecretKeyFragment extends ListFragment implements
*/
public static SelectSecretKeyFragment newInstance(boolean filterCertify) {
SelectSecretKeyFragment frag = new SelectSecretKeyFragment();
- Bundle args = new Bundle();
+ Bundle args = new Bundle();
args.putBoolean(ARG_FILTER_CERTIFY, filterCertify);
-
frag.setArguments(args);
return frag;
@@ -86,10 +85,10 @@ public class SelectSecretKeyFragment extends ListFragment implements
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
long masterKeyId = mAdapter.getMasterKeyId(position);
- String userId = mAdapter.getUserId(position);
+ Uri result = KeyRings.buildSecretKeyRingsByMasterKeyIdUri(String.valueOf(masterKeyId));
// return data to activity, which results in finishing it
- mActivity.afterListSelection(masterKeyId, userId);
+ mActivity.afterListSelection(result);
}
});
@@ -122,7 +121,7 @@ public class SelectSecretKeyFragment extends ListFragment implements
// These are the rows that we will retrieve.
long now = new Date().getTime() / 1000;
- String[] projection = new String[] {
+ String[] projection = new String[]{
KeyRings._ID,
KeyRings.MASTER_KEY_ID,
UserIds.USER_ID,
@@ -142,7 +141,7 @@ public class SelectSecretKeyFragment extends ListFragment implements
+ Keys.IS_REVOKED + " = '0' AND valid_keys." + Keys.CAN_SIGN
+ " = '1' AND valid_keys." + Keys.CREATION + " <= '" + now + "' AND "
+ "(valid_keys." + Keys.EXPIRY + " IS NULL OR valid_keys." + Keys.EXPIRY
- + " >= '" + now + "')) AS " + SelectKeyCursorAdapter.PROJECTION_ROW_VALID, };
+ + " >= '" + now + "')) AS " + SelectKeyCursorAdapter.PROJECTION_ROW_VALID,};
String orderBy = UserIds.USER_ID + " ASC";
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java
index 6bcb84f46..cbc0f4c5c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java
@@ -17,17 +17,15 @@
package org.sufficientlysecure.keychain.ui;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-
import android.app.Activity;
import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -36,17 +34,34 @@ import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton;
-public class SelectSecretKeyLayoutFragment extends Fragment {
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+
+public class SelectSecretKeyLayoutFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private TextView mKeyUserId;
private TextView mKeyUserIdRest;
+ private TextView mKeyMasterKeyIdHex;
+ private TextView mNoKeySelected;
private BootstrapButton mSelectKeyButton;
private Boolean mFilterCertify;
+ private Uri mReceivedUri = null;
+
private SelectSecretKeyCallback mCallback;
private static final int REQUEST_CODE_SELECT_KEY = 8882;
+ private static final int LOADER_ID = 0;
+
+ //The Projection we will retrieve, Master Key ID is for convenience sake,
+ //to avoid having to pass the Key Around
+ final String[] PROJECTION = new String[]{KeychainContract.UserIds.USER_ID
+ , KeychainContract.KeyRings.MASTER_KEY_ID};
+ final int INDEX_USER_ID = 0;
+ final int INDEX_MASTER_KEY_ID = 1;
+
public interface SelectSecretKeyCallback {
void onKeySelected(long secretKeyId);
}
@@ -59,34 +74,30 @@ public class SelectSecretKeyLayoutFragment extends Fragment {
mFilterCertify = filterCertify;
}
- public void selectKey(long secretKeyId) {
- if (secretKeyId == Id.key.none) {
- mKeyUserId.setText(R.string.api_settings_no_key);
- mKeyUserIdRest.setText("");
- } else {
- String uid = getResources().getString(R.string.user_id_no_name);
- String uidExtra = "";
- PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(
- getActivity(), secretKeyId);
- if (keyRing != null) {
- PGPSecretKey key = PgpKeyHelper.getMasterKey(keyRing);
- if (key != null) {
- String userId = PgpKeyHelper.getMainUserIdSafe(getActivity(), key);
- String chunks[] = userId.split(" <", 2);
- uid = chunks[0];
- if (chunks.length > 1) {
- uidExtra = "<" + chunks[1];
- }
- }
- }
- mKeyUserId.setText(uid);
- mKeyUserIdRest.setText(uidExtra);
- }
+ public void setNoKeySelected() {
+ mNoKeySelected.setVisibility(View.VISIBLE);
+ mKeyUserId.setVisibility(View.GONE);
+ mKeyUserIdRest.setVisibility(View.GONE);
+ mKeyMasterKeyIdHex.setVisibility(View.GONE);
+ }
+
+ public void setSelectedKeyData(String userName, String email, String masterKeyHex) {
+
+ mNoKeySelected.setVisibility(View.GONE);
+
+ mKeyUserId.setText(userName);
+ mKeyUserIdRest.setText(email);
+ mKeyMasterKeyIdHex.setText(masterKeyHex);
+
+ mKeyUserId.setVisibility(View.VISIBLE);
+ mKeyUserIdRest.setVisibility(View.VISIBLE);
+ mKeyMasterKeyIdHex.setVisibility(View.VISIBLE);
+
}
public void setError(String error) {
- mKeyUserId.requestFocus();
- mKeyUserId.setError(error);
+ mNoKeySelected.requestFocus();
+ mNoKeySelected.setError(error);
}
/**
@@ -96,8 +107,10 @@ public class SelectSecretKeyLayoutFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.select_secret_key_layout_fragment, container, false);
+ mNoKeySelected = (TextView) view.findViewById(R.id.no_key_selected);
mKeyUserId = (TextView) view.findViewById(R.id.select_secret_key_user_id);
mKeyUserIdRest = (TextView) view.findViewById(R.id.select_secret_key_user_id_rest);
+ mKeyMasterKeyIdHex = (TextView) view.findViewById(R.id.select_secret_key_master_key_hex);
mSelectKeyButton = (BootstrapButton) view
.findViewById(R.id.select_secret_key_select_key_button);
mFilterCertify = false;
@@ -111,6 +124,13 @@ public class SelectSecretKeyLayoutFragment extends Fragment {
return view;
}
+ //For AppSettingsFragment
+ public void selectKey(long masterKeyId) {
+ Uri buildUri = KeychainContract.KeyRings.buildSecretKeyRingsByMasterKeyIdUri(String.valueOf(masterKeyId));
+ mReceivedUri = buildUri;
+ getActivity().getSupportLoaderManager().restartLoader(LOADER_ID, null, this);
+ }
+
private void startSelectKeyActivity() {
Intent intent = new Intent(getActivity(), SelectSecretKeyActivity.class);
intent.putExtra(SelectSecretKeyActivity.EXTRA_FILTER_CERTIFY, mFilterCertify);
@@ -118,29 +138,74 @@ public class SelectSecretKeyLayoutFragment extends Fragment {
}
@Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ //We don't care about the Loader id
+ return new CursorLoader(getActivity(), mReceivedUri, PROJECTION, null, null, null);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ if (data.moveToFirst()) {
+ String userName, email, masterKeyHex;
+ String userID = data.getString(INDEX_USER_ID);
+ long masterKeyID = data.getLong(INDEX_MASTER_KEY_ID);
+
+ String splitUserID[] = PgpKeyHelper.splitUserId(userID);
+
+ if (splitUserID[0] != null) {
+ userName = splitUserID[0];
+ } else {
+ userName = getActivity().getResources().getString(R.string.user_id_no_name);
+ }
+
+ if (splitUserID[1] != null) {
+ email = splitUserID[1];
+ } else {
+ email = getActivity().getResources().getString(R.string.error_user_id_no_email);
+ }
+
+ //TODO Can the cursor return invalid values for the Master Key ?
+ masterKeyHex = PgpKeyHelper.convertKeyIdToHexShort(masterKeyID);
+
+ //Set the data
+ setSelectedKeyData(userName, email, masterKeyHex);
+
+ //Give value to the callback
+ mCallback.onKeySelected(masterKeyID);
+ } else {
+ //Set The empty View
+ setNoKeySelected();
+ }
+
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ return;
+ }
+
+ // Select Secret Key Activity delivers the intent which was sent by it using interface to Select
+ // Secret Key Fragment.Intent contains the passed Uri
+ @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode & 0xFFFF) {
- case REQUEST_CODE_SELECT_KEY: {
- long secretKeyId;
- if (resultCode == Activity.RESULT_OK) {
- Bundle bundle = data.getExtras();
- secretKeyId = bundle.getLong(SelectSecretKeyActivity.RESULT_EXTRA_MASTER_KEY_ID);
+ case REQUEST_CODE_SELECT_KEY: {
+ if (resultCode == Activity.RESULT_OK) {
+ mReceivedUri = data.getData();
- selectKey(secretKeyId);
+ //Must be restartLoader() or the data will not be updated on selecting a new key
+ getActivity().getSupportLoaderManager().restartLoader(LOADER_ID, null, this);
- // remove displayed errors
- mKeyUserId.setError(null);
+ mKeyUserId.setError(null);
- // give value back to callback
- mCallback.onKeySelected(secretKeyId);
+ }
+ break;
}
- break;
- }
- default:
- super.onActivityResult(requestCode, resultCode, data);
+ default:
+ super.onActivityResult(requestCode, resultCode, data);
- break;
+ break;
}
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
index 550d3047d..0e231e6a8 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
@@ -17,13 +17,6 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
@@ -36,8 +29,13 @@ import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.util.Log;
/**
* Sends the selected public key to a keyserver
@@ -59,7 +57,7 @@ public class UploadKeyActivity extends ActionBarActivity {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
- .getKeyServers());
+ .getKeyServers());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mKeyServerSpinner.setAdapter(adapter);
if (adapter.getCount() > 0) {
@@ -100,11 +98,11 @@ public class UploadKeyActivity extends ActionBarActivity {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // Message is received after uploading is done in ApgService
+ // Message is received after uploading is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) {
+ getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -113,7 +111,7 @@ public class UploadKeyActivity extends ActionBarActivity {
Toast.LENGTH_SHORT).show();
finish();
}
- };
+ }
};
// Create a new Messenger for the communication back
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index 0a452bc8a..3e7e6d7ce 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -29,13 +29,13 @@ import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
@@ -83,17 +83,23 @@ public class ViewKeyActivity extends ActionBarActivity {
selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB);
}
- mDataUri = getIntent().getData();
+ {
+ // normalize mDataUri to a "by row id" query, to ensure it works with any
+ // given valid /public/ query
+ long rowId = ProviderHelper.getRowId(this, getIntent().getData());
+ // TODO: handle (rowId == 0) with something else than a crash
+ mDataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(rowId));
+ }
Bundle mainBundle = new Bundle();
mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_main)),
- ViewKeyMainFragment.class, mainBundle, (selectedTab == 0 ? true : false));
+ ViewKeyMainFragment.class, mainBundle, (selectedTab == 0));
Bundle certBundle = new Bundle();
certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, mDataUri);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_certs)),
- ViewKeyCertsFragment.class, certBundle, (selectedTab == 1 ? true : false));
+ ViewKeyCertsFragment.class, certBundle, (selectedTab == 1));
}
@Override
@@ -107,7 +113,7 @@ public class ViewKeyActivity extends ActionBarActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
- Intent homeIntent = new Intent(this, KeyListPublicActivity.class);
+ Intent homeIntent = new Intent(this, KeyListActivity.class);
homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(homeIntent);
return true;
@@ -118,8 +124,11 @@ public class ViewKeyActivity extends ActionBarActivity {
uploadToKeyserver(mDataUri);
return true;
case R.id.menu_key_view_export_file:
- mExportHelper.showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR
- + "/pubexport.asc");
+ long masterKeyId =
+ ProviderHelper.getPublicMasterKeyId(this, Long.valueOf(mDataUri.getLastPathSegment()));
+ long[] ids = new long[]{masterKeyId};
+ mExportHelper.showExportKeysDialog(ids, Id.type.public_key,
+ Constants.Path.APP_DIR_FILE_PUB, null);
return true;
case R.id.menu_key_view_share_default_fingerprint:
shareKey(mDataUri, true);
@@ -154,7 +163,7 @@ public class ViewKeyActivity extends ActionBarActivity {
}
private void updateFromKeyserver(Uri dataUri) {
- long updateKeyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, mDataUri);
+ long updateKeyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, dataUri);
if (updateKeyId == 0) {
Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!");
@@ -173,7 +182,7 @@ public class ViewKeyActivity extends ActionBarActivity {
String content;
if (fingerprintOnly) {
byte[] fingerprintBlob = ProviderHelper.getFingerprint(this, dataUri);
- String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, false);
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
} else {
@@ -228,24 +237,12 @@ public class ViewKeyActivity extends ActionBarActivity {
Handler returnHandler = new Handler() {
@Override
public void handleMessage(Message message) {
- if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
- Bundle returnData = message.getData();
- if (returnData != null
- && returnData.containsKey(DeleteKeyDialogFragment.MESSAGE_NOT_DELETED)) {
- // we delete only this key, so MESSAGE_NOT_DELETED will solely contain this key
- Toast.makeText(ViewKeyActivity.this,
- getString(R.string.error_can_not_delete_contact)
- + getResources().getQuantityString(R.plurals.error_can_not_delete_info, 1),
- Toast.LENGTH_LONG).show();
- } else {
- setResult(RESULT_CANCELED);
- finish();
- }
- }
+ setResult(RESULT_CANCELED);
+ finish();
}
};
- mExportHelper.deleteKey(dataUri, Id.type.public_key, returnHandler);
+ mExportHelper.deleteKey(dataUri, returnHandler);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
index 59037d9ff..997ff9c7a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
@@ -18,10 +18,6 @@
package org.sufficientlysecure.keychain.ui;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-
import android.annotation.TargetApi;
import android.net.Uri;
import android.nfc.NdefMessage;
@@ -35,6 +31,9 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback,
@@ -66,7 +65,7 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
// get public keyring as byte array
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri,
- new long[] { masterKeyId });
+ new long[]{masterKeyId});
// Register callback to set NDEF message
mNfcAdapter.setNdefPushMessageCallback(this, this);
@@ -109,10 +108,10 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case NFC_SENT:
- Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG)
- .show();
- break;
+ case NFC_SENT:
+ Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG)
+ .show();
+ break;
}
}
};
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
index 36d3e6ace..02c04c11d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
@@ -24,9 +24,7 @@ import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
@@ -89,4 +87,4 @@ public class ViewKeyCertsFragment extends Fragment {
startActivity(signIntent);
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index 495764eaf..691be5fa9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui;
import android.content.Intent;
import android.database.Cursor;
+import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -36,6 +37,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -46,8 +48,8 @@ import org.sufficientlysecure.keychain.util.Log;
import java.util.Date;
-public class ViewKeyMainFragment extends Fragment implements
- LoaderManager.LoaderCallbacks<Cursor>{
+public class ViewKeyMainFragment extends Fragment implements
+ LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
@@ -59,7 +61,10 @@ public class ViewKeyMainFragment extends Fragment implements
private TextView mExpiry;
private TextView mCreation;
private TextView mFingerprint;
+ private TextView mSecretKey;
+ private BootstrapButton mActionEdit;
private BootstrapButton mActionEncrypt;
+ private BootstrapButton mActionCertify;
private ListView mUserIds;
private ListView mKeys;
@@ -85,9 +90,12 @@ public class ViewKeyMainFragment extends Fragment implements
mCreation = (TextView) view.findViewById(R.id.creation);
mExpiry = (TextView) view.findViewById(R.id.expiry);
mFingerprint = (TextView) view.findViewById(R.id.fingerprint);
+ mSecretKey = (TextView) view.findViewById(R.id.secret_key);
mUserIds = (ListView) view.findViewById(R.id.user_ids);
mKeys = (ListView) view.findViewById(R.id.keys);
+ mActionEdit = (BootstrapButton) view.findViewById(R.id.action_edit);
mActionEncrypt = (BootstrapButton) view.findViewById(R.id.action_encrypt);
+ mActionCertify = (BootstrapButton) view.findViewById(R.id.action_certify);
return view;
}
@@ -116,6 +124,53 @@ public class ViewKeyMainFragment extends Fragment implements
Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
+ { // label whether secret key is available, and edit button if it is
+ final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri);
+ if (ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) {
+ // set this attribute. this is a LITTLE unclean, but we have the info available
+ // right here, so why not.
+ mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
+ mSecretKey.setText(R.string.secret_key_yes);
+
+ // certify button
+ // TODO this button MIGHT be useful if the user wants to
+ // certify a private key with another...
+ // mActionCertify.setVisibility(View.GONE);
+
+ // edit button
+ mActionEdit.setVisibility(View.VISIBLE);
+ mActionEdit.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View view) {
+ Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
+ editIntent.setData(
+ KeychainContract
+ .KeyRings.buildSecretKeyRingsByMasterKeyIdUri(
+ Long.toString(masterKeyId)));
+ editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
+ startActivityForResult(editIntent, 0);
+ }
+ });
+ } else {
+ mSecretKey.setTextColor(Color.BLACK);
+ mSecretKey.setText(getResources().getString(R.string.secret_key_no));
+
+ // certify button
+ mActionCertify.setVisibility(View.VISIBLE);
+ // edit button
+ mActionEdit.setVisibility(View.GONE);
+ }
+
+ // TODO see todo note above, doing this here for now
+ mActionCertify.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View view) {
+ certifyKey(KeychainContract.KeyRings.buildPublicKeyRingsByMasterKeyIdUri(
+ Long.toString(masterKeyId)
+ ));
+ }
+ });
+
+ }
+
mActionEncrypt.setOnClickListener(new View.OnClickListener() {
@Override
@@ -137,21 +192,29 @@ public class ViewKeyMainFragment extends Fragment implements
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
}
- static final String[] KEYRING_PROJECTION = new String[]{KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID,
- KeychainContract.UserIds.USER_ID};
+ static final String[] KEYRING_PROJECTION =
+ new String[]{KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.UserIds.USER_ID};
static final int KEYRING_INDEX_ID = 0;
static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
static final int KEYRING_INDEX_USER_ID = 2;
- static final String[] USER_IDS_PROJECTION = new String[]{KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID,
- KeychainContract.UserIds.RANK,};
- // not the main user id
- static final String USER_IDS_SELECTION = KeychainContract.UserIds.RANK + " > 0 ";
- static final String USER_IDS_SORT_ORDER = KeychainContract.UserIds.USER_ID + " COLLATE LOCALIZED ASC";
-
- static final String[] KEYS_PROJECTION = new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
- KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY, KeychainContract.Keys.CAN_SIGN,
- KeychainContract.Keys.CAN_ENCRYPT, KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT};
+ static final String[] USER_IDS_PROJECTION =
+ new String[]{
+ KeychainContract.UserIds._ID,
+ KeychainContract.UserIds.USER_ID,
+ KeychainContract.UserIds.RANK,
+ };
+ static final String USER_IDS_SORT_ORDER =
+ KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC";
+
+ static final String[] KEYS_PROJECTION =
+ new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
+ KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM,
+ KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY,
+ KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT,
+ KeychainContract.Keys.IS_REVOKED, KeychainContract.Keys.CREATION,
+ KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT};
static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
static final int KEYS_INDEX_ID = 0;
static final int KEYS_INDEX_KEY_ID = 1;
@@ -161,9 +224,10 @@ public class ViewKeyMainFragment extends Fragment implements
static final int KEYS_INDEX_CAN_CERTIFY = 5;
static final int KEYS_INDEX_CAN_SIGN = 6;
static final int KEYS_INDEX_CAN_ENCRYPT = 7;
- static final int KEYS_INDEX_CREATION = 8;
- static final int KEYS_INDEX_EXPIRY = 9;
- static final int KEYS_INDEX_FINGERPRINT = 10;
+ static final int KEYS_INDEX_IS_REVOKED = 8;
+ static final int KEYS_INDEX_CREATION = 9;
+ static final int KEYS_INDEX_EXPIRY = 10;
+ static final int KEYS_INDEX_FINGERPRINT = 11;
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
@@ -179,7 +243,7 @@ public class ViewKeyMainFragment extends Fragment implements
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
- return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, USER_IDS_SELECTION, null,
+ return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null,
USER_IDS_SORT_ORDER);
}
case LOADER_ID_KEYS: {
@@ -224,8 +288,7 @@ public class ViewKeyMainFragment extends Fragment implements
if (data.moveToFirst()) {
// get key id from MASTER_KEY_ID
long keyId = data.getLong(KEYS_INDEX_KEY_ID);
-
- String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId);
+ String keyIdStr = PgpKeyHelper.convertKeyIdToHex(keyId);
mKeyId.setText(keyIdStr);
// get creation date from CREATION
@@ -234,8 +297,9 @@ public class ViewKeyMainFragment extends Fragment implements
} else {
Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000);
- mCreation.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
- creationDate));
+ mCreation.setText(
+ DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
+ creationDate));
}
// get expiry date from EXPIRY
@@ -244,8 +308,9 @@ public class ViewKeyMainFragment extends Fragment implements
} else {
Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000);
- mExpiry.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
- expiryDate));
+ mExpiry.setText(
+ DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
+ expiryDate));
}
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
@@ -257,10 +322,22 @@ public class ViewKeyMainFragment extends Fragment implements
// FALLBACK for old database entries
fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), mDataUri);
}
- String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, true);
- fingerprint = fingerprint.replace(" ", "\n");
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
+
+ mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
+ }
- mFingerprint.setText(fingerprint);
+ // hide encrypt button if no encryption key is available
+ boolean canEncrypt = false;
+ data.moveToFirst();
+ do {
+ if (data.getInt(KEYS_INDEX_CAN_ENCRYPT) == 1) {
+ canEncrypt = true;
+ break;
+ }
+ } while (data.moveToNext());
+ if (!canEncrypt) {
+ mActionEncrypt.setVisibility(View.GONE);
}
mKeysAdapter.swapCursor(data);
@@ -309,5 +386,4 @@ public class ViewKeyMainFragment extends Fragment implements
startActivity(signIntent);
}
-
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java
index 2ac19c1d9..5f2aec4fe 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java
@@ -22,24 +22,25 @@ package org.sufficientlysecure.keychain.ui.adapter;
* You can pass the result and an exception in it if an error occurred.
* Concept found at:
* https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader
+ *
* @param <T> - Typ of the result which is wrapped
*/
-public class AsyncTaskResultWrapper <T>{
+public class AsyncTaskResultWrapper<T> {
- private final T result;
- private final Exception error;
+ private final T mResult;
+ private final Exception mError;
- public AsyncTaskResultWrapper(T result, Exception error){
- this.result = result;
- this.error = error;
+ public AsyncTaskResultWrapper(T result, Exception error) {
+ this.mResult = result;
+ this.mError = error;
}
public T getResult() {
- return result;
+ return mResult;
}
public Exception getError() {
- return error;
+ return mError;
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java
new file mode 100644
index 000000000..a3ed08a4c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java
@@ -0,0 +1,65 @@
+/*
+ * 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.ui.adapter;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v4.widget.CursorAdapter;
+import android.text.Spannable;
+import android.text.style.ForegroundColorSpan;
+import org.sufficientlysecure.keychain.R;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class HighlightQueryCursorAdapter extends CursorAdapter {
+
+ private String mCurQuery;
+
+ public HighlightQueryCursorAdapter(Context context, Cursor c, int flags) {
+ super(context, c, flags);
+ mCurQuery = null;
+ }
+
+ public void setSearchQuery(String searchQuery) {
+ mCurQuery = searchQuery;
+ }
+
+ public String getSearchQuery() {
+ return mCurQuery;
+ }
+
+ protected Spannable highlightSearchQuery(String text) {
+ Spannable highlight = Spannable.Factory.getInstance().newSpannable(text);
+
+ if (mCurQuery != null) {
+ Pattern pattern = Pattern.compile("(?i)" + mCurQuery);
+ Matcher matcher = pattern.matcher(text);
+ if (matcher.find()) {
+ highlight.setSpan(
+ new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)),
+ matcher.start(),
+ matcher.end(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ return highlight;
+ } else {
+ return highlight;
+ }
+ }
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
index 52186b662..7d3166af9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
@@ -17,12 +17,6 @@
package org.sufficientlysecure.keychain.ui.adapter;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
@@ -37,11 +31,27 @@ import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.OtherHelper;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
protected LayoutInflater mInflater;
protected Activity mActivity;
- protected List<ImportKeysListEntry> data;
+ protected List<ImportKeysListEntry> mData;
+
+ static class ViewHolder {
+ private TextView mainUserId;
+ private TextView mainUserIdRest;
+ private TextView keyId;
+ private TextView fingerprint;
+ private TextView algorithm;
+ private TextView status;
+ }
public ImportKeysAdapter(Activity activity) {
super(activity, -1);
@@ -53,7 +63,7 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
public void setData(List<ImportKeysListEntry> data) {
clear();
if (data != null) {
- this.data = data;
+ this.mData = data;
// add data to extended ArrayAdapter
if (Build.VERSION.SDK_INT >= 11) {
@@ -67,14 +77,15 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
}
public List<ImportKeysListEntry> getData() {
- return data;
+ return mData;
}
public ArrayList<ImportKeysListEntry> getSelectedData() {
ArrayList<ImportKeysListEntry> selectedData = new ArrayList<ImportKeysListEntry>();
- for (ImportKeysListEntry entry : data) {
- if (entry.isSelected())
+ for (ImportKeysListEntry entry : mData) {
+ if (entry.isSelected()) {
selectedData.add(entry);
+ }
}
return selectedData;
}
@@ -85,17 +96,21 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
}
public View getView(int position, View convertView, ViewGroup parent) {
- ImportKeysListEntry entry = data.get(position);
-
- View view = mInflater.inflate(R.layout.import_keys_list_entry, null);
-
- TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
- TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- TextView keyId = (TextView) view.findViewById(R.id.keyId);
- TextView fingerprint = (TextView) view.findViewById(R.id.fingerprint);
- TextView algorithm = (TextView) view.findViewById(R.id.algorithm);
- TextView status = (TextView) view.findViewById(R.id.status);
-
+ ImportKeysListEntry entry = mData.get(position);
+ ViewHolder holder;
+ if (convertView == null) {
+ holder = new ViewHolder();
+ convertView = mInflater.inflate(R.layout.import_keys_list_entry, null);
+ holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId);
+ holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest);
+ holder.keyId = (TextView) convertView.findViewById(R.id.keyId);
+ holder.fingerprint = (TextView) convertView.findViewById(R.id.fingerprint);
+ holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm);
+ holder.status = (TextView) convertView.findViewById(R.id.status);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
// main user id
String userId = entry.userIds.get(0);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
@@ -105,39 +120,40 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
// show red user id if it is a secret key
if (entry.secretKey) {
userIdSplit[0] = mActivity.getString(R.string.secret_key) + " " + userIdSplit[0];
- mainUserId.setTextColor(Color.RED);
+ holder.mainUserId.setTextColor(Color.RED);
}
- mainUserId.setText(userIdSplit[0]);
+ holder.mainUserId.setText(userIdSplit[0]);
} else {
- mainUserId.setText(R.string.user_id_no_name);
+ holder.mainUserId.setText(R.string.user_id_no_name);
}
// email
if (userIdSplit[1] != null) {
- mainUserIdRest.setText(userIdSplit[1]);
- mainUserIdRest.setVisibility(View.VISIBLE);
+ holder.mainUserIdRest.setText(userIdSplit[1]);
+ holder.mainUserIdRest.setVisibility(View.VISIBLE);
} else {
- mainUserIdRest.setVisibility(View.GONE);
+ holder.mainUserIdRest.setVisibility(View.GONE);
}
- keyId.setText(entry.hexKeyId);
+ holder.keyId.setText(entry.keyIdHex);
- if (entry.fingerPrint != null) {
- fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint);
- fingerprint.setVisibility(View.VISIBLE);
+ if (entry.fingerPrintHex != null) {
+ holder.fingerprint.setText(PgpKeyHelper.colorizeFingerprint(entry.fingerPrintHex));
+ holder.fingerprint.setVisibility(View.VISIBLE);
} else {
- fingerprint.setVisibility(View.GONE);
+ holder.fingerprint.setVisibility(View.GONE);
}
- algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm);
+ holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm);
if (entry.revoked) {
- status.setText(R.string.revoked);
+ holder.status.setText(R.string.revoked);
} else {
- status.setVisibility(View.GONE);
+ holder.status.setVisibility(View.GONE);
}
- LinearLayout ll = (LinearLayout) view.findViewById(R.id.list);
+ LinearLayout ll = (LinearLayout) convertView.findViewById(R.id.list);
+ ll.removeAllViews();
if (entry.userIds.size() == 1) {
ll.setVisibility(View.GONE);
} else {
@@ -162,10 +178,10 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
}
}
- CheckBox cBox = (CheckBox) view.findViewById(R.id.selected);
+ CheckBox cBox = (CheckBox) convertView.findViewById(R.id.selected);
cBox.setChecked(entry.isSelected());
- return view;
+ return convertView;
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java
index 4a7a9c93a..9b20effc2 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java
@@ -19,11 +19,7 @@ package org.sufficientlysecure.keychain.ui.adapter;
import android.os.Parcel;
import android.os.Parcelable;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Date;
+import android.util.SparseArray;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKey;
@@ -33,35 +29,40 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+
public class ImportKeysListEntry implements Serializable, Parcelable {
private static final long serialVersionUID = -7797972103284992662L;
- public ArrayList<String> userIds;
+ public ArrayList<String> userIds;
public long keyId;
+ public String keyIdHex;
public boolean revoked;
public Date date; // TODO: not displayed
- public String fingerPrint;
- public String hexKeyId;
+ public String fingerPrintHex;
public int bitStrength;
public String algorithm;
public boolean secretKey;
- private boolean selected;
+ private boolean mSelected;
- private byte[] bytes = new byte[]{};
+ private byte[] mBytes = new byte[]{};
public ImportKeysListEntry(ImportKeysListEntry b) {
this.userIds = b.userIds;
this.keyId = b.keyId;
this.revoked = b.revoked;
this.date = b.date;
- this.fingerPrint = b.fingerPrint;
- this.hexKeyId = b.hexKeyId;
+ this.fingerPrintHex = b.fingerPrintHex;
+ this.keyIdHex = b.keyIdHex;
this.bitStrength = b.bitStrength;
this.algorithm = b.algorithm;
this.secretKey = b.secretKey;
- this.selected = b.selected;
- this.bytes = b.bytes;
+ this.mSelected = b.mSelected;
+ this.mBytes = b.mBytes;
}
public int describeContents() {
@@ -74,14 +75,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
dest.writeLong(keyId);
dest.writeByte((byte) (revoked ? 1 : 0));
dest.writeSerializable(date);
- dest.writeString(fingerPrint);
- dest.writeString(hexKeyId);
+ dest.writeString(fingerPrintHex);
+ dest.writeString(keyIdHex);
dest.writeInt(bitStrength);
dest.writeString(algorithm);
dest.writeByte((byte) (secretKey ? 1 : 0));
- dest.writeByte((byte) (selected ? 1 : 0));
- dest.writeInt(bytes.length);
- dest.writeByteArray(bytes);
+ dest.writeByte((byte) (mSelected ? 1 : 0));
+ dest.writeInt(mBytes.length);
+ dest.writeByteArray(mBytes);
}
public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() {
@@ -92,14 +93,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
vr.keyId = source.readLong();
vr.revoked = source.readByte() == 1;
vr.date = (Date) source.readSerializable();
- vr.fingerPrint = source.readString();
- vr.hexKeyId = source.readString();
+ vr.fingerPrintHex = source.readString();
+ vr.keyIdHex = source.readString();
vr.bitStrength = source.readInt();
vr.algorithm = source.readString();
vr.secretKey = source.readByte() == 1;
- vr.selected = source.readByte() == 1;
- vr.bytes = new byte[source.readInt()];
- source.readByteArray(vr.bytes);
+ vr.mSelected = source.readByte() == 1;
+ vr.mBytes = new byte[source.readInt()];
+ source.readByteArray(vr.mBytes);
return vr;
}
@@ -109,34 +110,105 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
}
};
- public long getKeyId() {
- return keyId;
+ public String getKeyIdHex() {
+ return keyIdHex;
}
public byte[] getBytes() {
- return bytes;
+ return mBytes;
}
public void setBytes(byte[] bytes) {
- this.bytes = bytes;
+ this.mBytes = bytes;
+ }
+
+ public boolean isSelected() {
+ return mSelected;
+ }
+
+ public void setSelected(boolean selected) {
+ this.mSelected = selected;
+ }
+
+ public long getKeyId() {
+ return keyId;
+ }
+
+ public void setKeyId(long keyId) {
+ this.keyId = keyId;
+ }
+
+ public void setKeyIdHex(String keyIdHex) {
+ this.keyIdHex = keyIdHex;
+ }
+
+ public boolean isRevoked() {
+ return revoked;
+ }
+
+ public void setRevoked(boolean revoked) {
+ this.revoked = revoked;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public String getFingerPrintHex() {
+ return fingerPrintHex;
+ }
+
+ public void setFingerPrintHex(String fingerPrintHex) {
+ this.fingerPrintHex = fingerPrintHex;
+ }
+
+ public int getBitStrength() {
+ return bitStrength;
+ }
+
+ public void setBitStrength(int bitStrength) {
+ this.bitStrength = bitStrength;
+ }
+
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ public void setAlgorithm(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ public boolean isSecretKey() {
+ return secretKey;
+ }
+
+ public void setSecretKey(boolean secretKey) {
+ this.secretKey = secretKey;
+ }
+
+ public ArrayList<String> getUserIds() {
+ return userIds;
+ }
+
+ public void setUserIds(ArrayList<String> userIds) {
+ this.userIds = userIds;
}
/**
* Constructor for later querying from keyserver
*/
public ImportKeysListEntry() {
+ // keys from keyserver are always public keys
secretKey = false;
+ // do not select by default
+ mSelected = false;
userIds = new ArrayList<String>();
}
- public boolean isSelected() {
- return selected;
- }
-
- public void setSelected(boolean selected) {
- this.selected = selected;
- }
-
/**
* Constructor based on key object, used for import from NFC, QR Codes, files
*/
@@ -144,13 +216,13 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
public ImportKeysListEntry(PGPKeyRing pgpKeyRing) {
// save actual key object into entry, used to import it later
try {
- this.bytes = pgpKeyRing.getEncoded();
+ this.mBytes = pgpKeyRing.getEncoded();
} catch (IOException e) {
Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e);
}
// selected is default
- this.selected = true;
+ this.mSelected = true;
if (pgpKeyRing instanceof PGPSecretKeyRing) {
secretKey = true;
@@ -162,27 +234,39 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
for (String userId : new IterableIterator<String>(pgpKeyRing.getPublicKey().getUserIDs())) {
userIds.add(userId);
}
+
this.keyId = pgpKeyRing.getPublicKey().getKeyID();
+ this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId);
this.revoked = pgpKeyRing.getPublicKey().isRevoked();
- this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey()
- .getFingerprint(), true);
- this.hexKeyId = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId);
+ this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey()
+ .getFingerprint());
this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength();
- int algorithm = pgpKeyRing.getPublicKey().getAlgorithm();
- if (algorithm == PGPPublicKey.RSA_ENCRYPT || algorithm == PGPPublicKey.RSA_GENERAL
- || algorithm == PGPPublicKey.RSA_SIGN) {
- this.algorithm = "RSA";
- } else if (algorithm == PGPPublicKey.DSA) {
- this.algorithm = "DSA";
- } else if (algorithm == PGPPublicKey.ELGAMAL_ENCRYPT
- || algorithm == PGPPublicKey.ELGAMAL_GENERAL) {
- this.algorithm = "ElGamal";
- } else if (algorithm == PGPPublicKey.EC || algorithm == PGPPublicKey.ECDSA) {
- this.algorithm = "ECC";
- } else {
- // TODO: with resources
- this.algorithm = "unknown";
- }
+ final int algorithm = pgpKeyRing.getPublicKey().getAlgorithm();
+ this.algorithm = getAlgorithmFromId(algorithm);
+ }
+
+ /**
+ * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
+ */
+ private final static SparseArray<String> ALGORITHM_IDS = new SparseArray<String>() {{
+ put(-1, "unknown"); // TODO: with resources
+ put(0, "unencrypted");
+ put(PGPPublicKey.RSA_GENERAL, "RSA");
+ put(PGPPublicKey.RSA_ENCRYPT, "RSA");
+ put(PGPPublicKey.RSA_SIGN, "RSA");
+ put(PGPPublicKey.ELGAMAL_ENCRYPT, "ElGamal");
+ put(PGPPublicKey.ELGAMAL_GENERAL, "ElGamal");
+ put(PGPPublicKey.DSA, "DSA");
+ put(PGPPublicKey.EC, "ECC");
+ put(PGPPublicKey.ECDSA, "ECC");
+ put(PGPPublicKey.ECDH, "ECC");
+ }};
+
+ /**
+ * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
+ */
+ public static String getAlgorithmFromId(int algorithmId) {
+ return (ALGORITHM_IDS.get(algorithmId) != null ? ALGORITHM_IDS.get(algorithmId) : ALGORITHM_IDS.get(-1));
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
index 76649b27b..c9983213c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
@@ -17,11 +17,8 @@
package org.sufficientlysecure.keychain.ui.adapter;
-import java.io.BufferedInputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
+import android.content.Context;
+import android.support.v4.content.AsyncTaskLoader;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPUtil;
@@ -30,16 +27,35 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
-import android.content.Context;
-import android.support.v4.content.AsyncTaskLoader;
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+public class ImportKeysListLoader
+ extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
+
+ public static class FileHasNoContent extends Exception {
+
+ }
+
+ public static class NonPgpPart extends Exception {
+ private int mCount;
+
+ public NonPgpPart(int count) {
+ this.mCount = count;
+ }
+
+ public int getCount() {
+ return mCount;
+ }
+ }
-public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
Context mContext;
InputData mInputData;
- ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>();
- AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
+ ArrayList<ImportKeysListEntry> mData = new ArrayList<ImportKeysListEntry>();
+ AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
public ImportKeysListLoader(Context context, InputData inputData) {
super(context);
@@ -50,16 +66,16 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
@Override
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
- entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, null);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, null);
if (mInputData == null) {
Log.e(Constants.TAG, "Input data is null!");
- return entryListWrapper;
+ return mEntryListWrapper;
}
generateListOfKeyrings(mInputData);
- return entryListWrapper;
+ return mEntryListWrapper;
}
@Override
@@ -87,11 +103,15 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
/**
* Reads all PGPKeyRing objects from input
- *
- * @param keyringBytes
+ *
+ * @param inputData
* @return
*/
private void generateListOfKeyrings(InputData inputData) {
+
+ boolean isEmpty = true;
+ int nonPgpCounter = 0;
+
PositionAwareInputStream progressIn = new PositionAwareInputStream(
inputData.getInputStream());
@@ -103,6 +123,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
// read all available blocks... (asc files can contain many blocks with BEGIN END)
while (bufferedInput.available() > 0) {
+ isEmpty = false;
InputStream in = PGPUtil.getDecoderStream(bufferedInput);
PGPObjectFactory objectFactory = new PGPObjectFactory(in);
@@ -116,17 +137,31 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
addToData(newKeyring);
} else {
Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!");
+ nonPgpCounter++;
}
}
}
} catch (Exception e) {
Log.e(Constants.TAG, "Exception on parsing key file!", e);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, e);
+ nonPgpCounter = 0;
+ }
+
+ if (isEmpty) {
+ Log.e(Constants.TAG, "File has no content!", new FileHasNoContent());
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
+ (mData, new FileHasNoContent());
+ }
+
+ if (nonPgpCounter > 0) {
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
+ (mData, new NonPgpPart(nonPgpCounter));
}
}
private void addToData(PGPKeyRing keyring) {
ImportKeysListEntry item = new ImportKeysListEntry(keyring);
- data.add(item);
+ mData.add(item);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
index 3a3b6e58b..a4dd06e40 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
@@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.HkpKeyServer;
import org.sufficientlysecure.keychain.util.KeyServer;
@@ -27,14 +26,15 @@ import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
-public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
+public class ImportKeysListServerLoader
+ extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
Context mContext;
String mServerQuery;
String mKeyServer;
- private ArrayList<ImportKeysListEntry> entryList = new ArrayList<ImportKeysListEntry>();
- private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
+ private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<ImportKeysListEntry>();
+ private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) {
super(context);
@@ -46,16 +46,16 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW
@Override
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
- entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
if (mServerQuery == null) {
Log.e(Constants.TAG, "mServerQuery is null!");
- return entryListWrapper;
+ return mEntryListWrapper;
}
queryServer(mServerQuery, mKeyServer);
- return entryListWrapper;
+ return mEntryListWrapper;
}
@Override
@@ -89,18 +89,19 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW
try {
ArrayList<ImportKeysListEntry> searchResult = server.search(query);
+ mEntryList.clear();
// add result to data
- entryList.addAll(searchResult);
- entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
+ mEntryList.addAll(searchResult);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
} catch (KeyServer.InsufficientQuery e) {
Log.e(Constants.TAG, "InsufficientQuery", e);
- entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
} catch (KeyServer.QueryException e) {
Log.e(Constants.TAG, "QueryException", e);
- entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
} catch (KeyServer.TooManyResponses e) {
Log.e(Constants.TAG, "TooManyResponses", e);
- entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
deleted file mode 100644
index ac505adfb..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2013 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.adapter;
-
-import java.util.HashMap;
-import java.util.Set;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.util.Log;
-
-import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Color;
-import android.support.v4.widget.CursorAdapter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-/**
- * Implements StickyListHeadersAdapter from library
- */
-public class KeyListPublicAdapter extends CursorAdapter implements StickyListHeadersAdapter {
- private LayoutInflater mInflater;
- private int mSectionColumnIndex;
- private int mIndexUserId;
- private int mIndexIsRevoked;
-
- @SuppressLint("UseSparseArrays")
- private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
-
- public KeyListPublicAdapter(Context context, Cursor c, int flags, int sectionColumnIndex) {
- super(context, c, flags);
-
- mInflater = LayoutInflater.from(context);
- mSectionColumnIndex = sectionColumnIndex;
- initIndex(c);
- }
-
- @Override
- public Cursor swapCursor(Cursor newCursor) {
- initIndex(newCursor);
-
- return super.swapCursor(newCursor);
- }
-
- /**
- * Get column indexes for performance reasons just once in constructor and swapCursor. For a
- * performance comparison see http://stackoverflow.com/a/17999582
- *
- * @param cursor
- */
- private void initIndex(Cursor cursor) {
- if (cursor != null) {
- mIndexUserId = cursor.getColumnIndexOrThrow(KeychainContract.UserIds.USER_ID);
- mIndexIsRevoked = cursor.getColumnIndexOrThrow(KeychainContract.Keys.IS_REVOKED);
- }
- }
-
- /**
- * Bind cursor data to the item list view
- * <p/>
- * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. Thus
- * no ViewHolder is required here.
- */
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
- TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- TextView revoked = (TextView) view.findViewById(R.id.revoked);
-
- String userId = cursor.getString(mIndexUserId);
- String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
- if (userIdSplit[0] != null) {
- mainUserId.setText(userIdSplit[0]);
- } else {
- mainUserId.setText(R.string.user_id_no_name);
- }
- if (userIdSplit[1] != null) {
- mainUserIdRest.setText(userIdSplit[1]);
- mainUserIdRest.setVisibility(View.VISIBLE);
- } else {
- mainUserIdRest.setVisibility(View.GONE);
- }
-
- boolean isRevoked = cursor.getInt(mIndexIsRevoked) > 0;
- if (isRevoked) {
- revoked.setVisibility(View.VISIBLE);
- } else {
- revoked.setVisibility(View.GONE);
- }
- }
-
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.key_list_public_item, null);
- }
-
- /**
- * Creates a new header view and binds the section headers to it. It uses the ViewHolder
- * pattern. Most functionality is similar to getView() from Android's CursorAdapter.
- * <p/>
- * NOTE: The variables mDataValid and mCursor are available due to the super class
- * CursorAdapter.
- */
- @Override
- public View getHeaderView(int position, View convertView, ViewGroup parent) {
- HeaderViewHolder holder;
- if (convertView == null) {
- holder = new HeaderViewHolder();
- convertView = mInflater.inflate(R.layout.key_list_public_header, parent, false);
- holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text);
- convertView.setTag(holder);
- } else {
- holder = (HeaderViewHolder) convertView.getTag();
- }
-
- if (!mDataValid) {
- // no data available at this point
- Log.d(Constants.TAG, "getHeaderView: No data available at this point!");
- return convertView;
- }
-
- if (!mCursor.moveToPosition(position)) {
- throw new IllegalStateException("couldn't move cursor to position " + position);
- }
-
- // set header text as first char in user id
- String userId = mCursor.getString(mSectionColumnIndex);
- String headerText = convertView.getResources().getString(R.string.user_id_no_name);
- if (userId != null && userId.length() > 0) {
- headerText = "" + mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0);
- }
- holder.text.setText(headerText);
- return convertView;
- }
-
- /**
- * Header IDs should be static, position=1 should always return the same Id that is.
- */
- @Override
- public long getHeaderId(int position) {
- if (!mDataValid) {
- // no data available at this point
- Log.d(Constants.TAG, "getHeaderView: No data available at this point!");
- return -1;
- }
-
- if (!mCursor.moveToPosition(position)) {
- throw new IllegalStateException("couldn't move cursor to position " + position);
- }
-
- // return the first character of the name as ID because this is what
- // headers are based upon
- String userId = mCursor.getString(mSectionColumnIndex);
- if (userId != null && userId.length() > 0) {
- return userId.subSequence(0, 1).charAt(0);
- } else {
- return Long.MAX_VALUE;
- }
- }
-
- class HeaderViewHolder {
- TextView text;
- }
-
- /**
- * -------------------------- MULTI-SELECTION METHODS --------------
- */
- public void setNewSelection(int position, boolean value) {
- mSelection.put(position, value);
- notifyDataSetChanged();
- }
-
- public boolean isPositionChecked(int position) {
- Boolean result = mSelection.get(position);
- return result == null ? false : result;
- }
-
- public Set<Integer> getCurrentCheckedPosition() {
- return mSelection.keySet();
- }
-
- public void removeSelection(int position) {
- mSelection.remove(position);
- notifyDataSetChanged();
- }
-
- public void clearSelection() {
- mSelection.clear();
- notifyDataSetChanged();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- // let the adapter handle setting up the row views
- View v = super.getView(position, convertView, parent);
-
- /**
- * Change color for multi-selection
- */
- // default color
- v.setBackgroundColor(Color.TRANSPARENT);
- if (mSelection.get(position) != null && mSelection.get(position).booleanValue()) {
- // this is a selected position, change color!
- v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
- }
- return v;
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java
deleted file mode 100644
index 11d1e8c17..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2013 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.adapter;
-
-import java.util.HashMap;
-import java.util.Set;
-
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Color;
-import android.support.v4.widget.CursorAdapter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-public class KeyListSecretAdapter extends CursorAdapter {
- private LayoutInflater mInflater;
-
- private int mIndexUserId;
-
- @SuppressLint("UseSparseArrays")
- private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
-
- public KeyListSecretAdapter(Context context, Cursor c, int flags) {
- super(context, c, flags);
-
- mInflater = LayoutInflater.from(context);
- initIndex(c);
- }
-
- @Override
- public Cursor swapCursor(Cursor newCursor) {
- initIndex(newCursor);
-
- return super.swapCursor(newCursor);
- }
-
- /**
- * Get column indexes for performance reasons just once in constructor and swapCursor. For a
- * performance comparison see http://stackoverflow.com/a/17999582
- *
- * @param cursor
- */
- private void initIndex(Cursor cursor) {
- if (cursor != null) {
- mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID);
- }
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
- TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
-
- String userId = cursor.getString(mIndexUserId);
- String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
-
- if (userIdSplit[0] != null) {
- mainUserId.setText(userIdSplit[0]);
- } else {
- mainUserId.setText(R.string.user_id_no_name);
- }
- if (userIdSplit[1] != null) {
- mainUserIdRest.setText(userIdSplit[1]);
- } else {
- mainUserIdRest.setText("");
- }
- }
-
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.key_list_secret_item, null);
- }
-
- /** -------------------------- MULTI-SELECTION METHODS -------------- */
- public void setNewSelection(int position, boolean value) {
- mSelection.put(position, value);
- notifyDataSetChanged();
- }
-
- public boolean isPositionChecked(int position) {
- Boolean result = mSelection.get(position);
- return result == null ? false : result;
- }
-
- public Set<Integer> getCurrentCheckedPosition() {
- return mSelection.keySet();
- }
-
- public void removeSelection(int position) {
- mSelection.remove(position);
- notifyDataSetChanged();
- }
-
- public void clearSelection() {
- mSelection.clear();
- notifyDataSetChanged();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- // let the adapter handle setting up the row views
- View v = super.getView(position, convertView, parent);
-
- /**
- * Change color for multi-selection
- */
- // default color
- v.setBackgroundColor(Color.TRANSPARENT);
- if (mSelection.get(position) != null) {
- // this is a selected position, change color!
- v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
- }
- return v;
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java
index 78f7b1f7e..c997599bd 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java
@@ -17,15 +17,11 @@
package org.sufficientlysecure.keychain.ui.adapter;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
import android.content.Context;
import android.widget.ArrayAdapter;
+import java.util.*;
+
public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
private final HashMap<Integer, String> mData;
private final int[] mKeys;
@@ -98,4 +94,4 @@ public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
}
return -1;
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
index d44dd5890..fbbb9caa4 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
@@ -17,23 +17,22 @@
package org.sufficientlysecure.keychain.ui.adapter;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-
import android.content.Context;
import android.database.Cursor;
-import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-public class SelectKeyCursorAdapter extends CursorAdapter {
+
+public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
protected int mKeyType;
@@ -45,17 +44,16 @@ public class SelectKeyCursorAdapter extends CursorAdapter {
private int mIndexProjectionValid;
private int mIndexProjectionAvailable;
- public final static String PROJECTION_ROW_AVAILABLE = "available";
- public final static String PROJECTION_ROW_VALID = "valid";
+ public static final String PROJECTION_ROW_AVAILABLE = "available";
+ public static final String PROJECTION_ROW_VALID = "valid";
public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView,
- int keyType) {
+ int keyType) {
super(context, c, flags);
mInflater = LayoutInflater.from(context);
mListView = listView;
mKeyType = keyType;
-
initIndex(c);
}
@@ -69,7 +67,7 @@ public class SelectKeyCursorAdapter extends CursorAdapter {
/**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582
- *
+ *
* @param cursor
*/
private void initIndex(Cursor cursor) {
@@ -104,12 +102,12 @@ public class SelectKeyCursorAdapter extends CursorAdapter {
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) {
- mainUserId.setText(userIdSplit[0]);
+ mainUserId.setText(highlightSearchQuery(userIdSplit[0]));
} else {
mainUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
- mainUserIdRest.setText(userIdSplit[1]);
+ mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
} else {
mainUserIdRest.setText("");
}
@@ -117,7 +115,7 @@ public class SelectKeyCursorAdapter extends CursorAdapter {
// TODO: needed to key id to no?
keyId.setText(R.string.no_key);
long masterKeyId = cursor.getLong(mIndexMasterKeyId);
- keyId.setText(PgpKeyHelper.convertKeyIdToHex(masterKeyId));
+ keyId.setText(PgpKeyHelper.convertKeyIdToHexShort(masterKeyId));
// TODO: needed to set unknown_status?
status.setText(R.string.unknown_status);
@@ -164,5 +162,4 @@ public class SelectKeyCursorAdapter extends CursorAdapter {
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mInflater.inflate(R.layout.select_key_item, null);
}
-
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
index 924a70897..f435d46ef 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java
@@ -1,3 +1,20 @@
+/*
+ * 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.adapter;
import android.content.Context;
@@ -19,12 +36,12 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
- private final Class<?> clss;
- private final Bundle args;
+ private final Class<?> mClss;
+ private final Bundle mArgs;
- TabInfo(Class<?> _class, Bundle _args) {
- clss = _class;
- args = _args;
+ TabInfo(Class<?> mClss, Bundle mArgs) {
+ this.mClss = mClss;
+ this.mArgs = mArgs;
}
}
@@ -54,7 +71,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
- return Fragment.instantiate(mContext, info.clss.getName(), info.args);
+ return Fragment.instantiate(mContext, info.mClss.getName(), info.mArgs);
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
@@ -81,4 +98,4 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java
index 54c7eb60e..9d60c1530 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java
@@ -17,18 +17,23 @@
package org.sufficientlysecure.keychain.ui.adapter;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
-
import android.content.Context;
+import android.content.res.ColorStateList;
import android.database.Cursor;
+import android.graphics.Color;
import android.support.v4.widget.CursorAdapter;
+import android.text.format.DateFormat;
import android.view.LayoutInflater;
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.helper.OtherHelper;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
+
+import java.util.Date;
public class ViewKeyKeysAdapter extends CursorAdapter {
private LayoutInflater mInflater;
@@ -40,6 +45,10 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
private int mIndexCanCertify;
private int mIndexCanEncrypt;
private int mIndexCanSign;
+ private int mIndexRevokedKey;
+ private int mIndexExpiry;
+
+ private ColorStateList mDefaultTextColor;
public ViewKeyKeysAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
@@ -59,7 +68,7 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
/**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582
- *
+ *
* @param cursor
*/
private void initIndex(Cursor cursor) {
@@ -71,6 +80,8 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
mIndexCanCertify = cursor.getColumnIndexOrThrow(Keys.CAN_CERTIFY);
mIndexCanEncrypt = cursor.getColumnIndexOrThrow(Keys.CAN_ENCRYPT);
mIndexCanSign = cursor.getColumnIndexOrThrow(Keys.CAN_SIGN);
+ mIndexRevokedKey = cursor.getColumnIndexOrThrow(Keys.IS_REVOKED);
+ mIndexExpiry = cursor.getColumnIndexOrThrow(Keys.EXPIRY);
}
}
@@ -78,17 +89,18 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
public void bindView(View view, Context context, Cursor cursor) {
TextView keyId = (TextView) view.findViewById(R.id.keyId);
TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
+ TextView keyExpiry = (TextView) view.findViewById(R.id.keyExpiry);
ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey);
ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey);
ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
+ ImageView revokedKeyIcon = (ImageView) view.findViewById(R.id.ic_revokedKey);
- String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId));
+ String keyIdStr = PgpKeyHelper.convertKeyIdToHexShort(cursor.getLong(mIndexKeyId));
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm),
cursor.getInt(mIndexKeySize));
keyId.setText(keyIdStr);
-
keyDetails.setText("(" + algorithmStr + ")");
if (cursor.getInt(mIndexIsMasterKey) != 1) {
@@ -114,11 +126,52 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
} else {
signIcon.setVisibility(View.VISIBLE);
}
+
+ boolean valid = true;
+ if (cursor.getInt(mIndexRevokedKey) > 0) {
+ revokedKeyIcon.setVisibility(View.VISIBLE);
+
+ valid = false;
+ } else {
+ keyId.setTextColor(mDefaultTextColor);
+ keyDetails.setTextColor(mDefaultTextColor);
+ keyExpiry.setTextColor(mDefaultTextColor);
+
+ revokedKeyIcon.setVisibility(View.GONE);
+ }
+
+ if (!cursor.isNull(mIndexExpiry)) {
+ Date expiryDate = new Date(cursor.getLong(mIndexExpiry) * 1000);
+
+ valid = valid && expiryDate.after(new Date());
+ keyExpiry.setText("(" +
+ context.getString(R.string.label_expiry) + ": " +
+ DateFormat.getDateFormat(context).format(expiryDate) + ")");
+
+ keyExpiry.setVisibility(View.VISIBLE);
+ }
+ else {
+ keyExpiry.setVisibility(View.GONE);
+ }
+ // if key is expired or revoked, strike through text
+ if (!valid) {
+ keyId.setText(OtherHelper.strikeOutText(keyId.getText()));
+ keyDetails.setText(OtherHelper.strikeOutText(keyDetails.getText()));
+ keyExpiry.setText(OtherHelper.strikeOutText(keyExpiry.getText()));
+ }
+ keyId.setEnabled(valid);
+ keyDetails.setEnabled(valid);
+ keyExpiry.setEnabled(valid);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.view_key_keys_item, null);
+ View view = mInflater.inflate(R.layout.view_key_keys_item, null);
+ if (mDefaultTextColor == null) {
+ TextView keyId = (TextView) view.findViewById(R.id.keyId);
+ mDefaultTextColor = keyId.getTextColors();
+ }
+ return view;
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java
index cf8699417..61572b9ce 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java
@@ -17,33 +17,54 @@
package org.sufficientlysecure.keychain.ui.adapter;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.TextView;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
+
+import java.util.ArrayList;
public class ViewKeyUserIdsAdapter extends CursorAdapter {
private LayoutInflater mInflater;
- private int mIndexUserId;
+ private int mIndexUserId, mIndexRank;
- public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags) {
+ final private ArrayList<Boolean> mCheckStates;
+
+ public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) {
super(context, c, flags);
mInflater = LayoutInflater.from(context);
+ mCheckStates = showCheckBoxes ? new ArrayList<Boolean>() : null;
+
initIndex(c);
}
+ public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags) {
+ this(context, c, flags, false);
+ }
@Override
public Cursor swapCursor(Cursor newCursor) {
initIndex(newCursor);
+ if(mCheckStates != null) {
+ mCheckStates.clear();
+ if(newCursor != null) {
+ int count = newCursor.getCount();
+ mCheckStates.ensureCapacity(count);
+ // initialize to true (use case knowledge: we usually want to sign all uids)
+ for(int i = 0; i < count; i++)
+ mCheckStates.add(true);
+ }
+ }
return super.swapCursor(newCursor);
}
@@ -51,26 +72,73 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter {
/**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582
- *
+ *
* @param cursor
*/
private void initIndex(Cursor cursor) {
if (cursor != null) {
mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID);
+ mIndexRank = cursor.getColumnIndexOrThrow(UserIds.RANK);
}
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
- String userIdStr = cursor.getString(mIndexUserId);
- TextView userId = (TextView) view.findViewById(R.id.userId);
- userId.setText(userIdStr);
+ TextView vRank = (TextView) view.findViewById(R.id.rank);
+ TextView vUserId = (TextView) view.findViewById(R.id.userId);
+ TextView vAddress = (TextView) view.findViewById(R.id.address);
+
+ vRank.setText(Integer.toString(cursor.getInt(mIndexRank)));
+
+ String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexUserId));
+ if (userId[0] != null) {
+ vUserId.setText(userId[0]);
+ } else {
+ vUserId.setText(R.string.user_id_no_name);
+ }
+ vAddress.setText(userId[1]);
+
+ // don't care further if checkboxes aren't shown
+ if(mCheckStates == null)
+ return;
+
+ final CheckBox vCheckBox = (CheckBox) view.findViewById(R.id.checkBox);
+ final int position = cursor.getPosition();
+ vCheckBox.setClickable(false);
+ vCheckBox.setChecked(mCheckStates.get(position));
+ vCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
+ mCheckStates.set(position, b);
+ }
+ });
+ view.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ vCheckBox.toggle();
+ }
+ });
+
+ }
+
+ public ArrayList<String> getSelectedUserIds() {
+ ArrayList<String> result = new ArrayList<String>();
+ for(int i = 0; i < mCheckStates.size(); i++) {
+ if(mCheckStates.get(i)) {
+ mCursor.moveToPosition(i);
+ result.add(mCursor.getString(mIndexUserId));
+ }
+ }
+ return result;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.view_key_userids_item, null);
+ View view = mInflater.inflate(R.layout.view_key_userids_item, null);
+ // only need to do this once ever, since mShowCheckBoxes is final
+ view.findViewById(R.id.checkBox).setVisibility(mCheckStates != null ? View.VISIBLE : View.GONE);
+ return view;
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java
index 2b8cba857..20b70658c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java
@@ -23,7 +23,6 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
-
import org.sufficientlysecure.keychain.R;
public class BadImportKeyDialogFragment extends DialogFragment {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java
index 98b677511..ffb45afc5 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java
@@ -25,14 +25,14 @@ import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
-
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Choice;
-import java.util.Vector;
+import java.util.ArrayList;
public class CreateKeyDialogFragment extends DialogFragment {
@@ -78,7 +78,7 @@ public class CreateKeyDialogFragment extends DialogFragment {
boolean wouldBeMasterKey = (childCount == 0);
final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm);
- Vector<Choice> choices = new Vector<Choice>();
+ ArrayList<Choice> choices = new ArrayList<Choice>();
choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString(
R.string.dsa)));
if (!wouldBeMasterKey) {
@@ -114,21 +114,8 @@ public class CreateKeyDialogFragment extends DialogFragment {
public void onClick(DialogInterface di, int id) {
di.dismiss();
try {
- int nKeyIndex = keySize.getSelectedItemPosition();
- switch (nKeyIndex) {
- case 0:
- mNewKeySize = 512;
- break;
- case 1:
- mNewKeySize = 1024;
- break;
- case 2:
- mNewKeySize = 2048;
- break;
- case 3:
- mNewKeySize = 4096;
- break;
- }
+ final String selectedItem = (String) keySize.getSelectedItem();
+ mNewKeySize = Integer.parseInt(selectedItem);
} catch (NumberFormatException e) {
mNewKeySize = 0;
}
@@ -146,7 +133,26 @@ public class CreateKeyDialogFragment extends DialogFragment {
}
});
- return dialog.create();
+ final AlertDialog alertDialog = dialog.create();
+
+ final AdapterView.OnItemSelectedListener weakRsaListener = new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ final Choice selectedAlgorithm = (Choice)algorithm.getSelectedItem();
+ final int selectedKeySize = Integer.parseInt((String)keySize.getSelectedItem());
+ final boolean isWeakRsa = (selectedAlgorithm.getId() == Id.choice.algorithm.rsa && selectedKeySize <= 1024);
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(!isWeakRsa);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ };
+
+ keySize.setOnItemSelectedListener(weakRsaListener);
+ algorithm.setOnItemSelectedListener(weakRsaListener);
+
+ return alertDialog;
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java
index cd8bc79a9..b4c38184c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java
@@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
@@ -32,6 +28,9 @@ import android.os.Messenger;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
public class DeleteFileDialogFragment extends DialogFragment {
private static final String ARG_DELETE_FILE = "delete_file";
@@ -67,7 +66,7 @@ public class DeleteFileDialogFragment extends DialogFragment {
alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile));
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-
+
@Override
public void onClick(DialogInterface dialog, int id) {
dismiss();
@@ -83,19 +82,23 @@ public class DeleteFileDialogFragment extends DialogFragment {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance(
- R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL, false, null);
-
- // Message is received after deleting is done in ApgService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) {
+ getString(R.string.progress_deleting_securely),
+ ProgressDialog.STYLE_HORIZONTAL,
+ false,
+ null);
+
+ // Message is received after deleting is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler =
+ new KeychainIntentServiceHandler(activity, deletingDialog) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
Toast.makeText(activity, R.string.file_delete_successful,
Toast.LENGTH_SHORT).show();
}
- };
+ }
};
// Create a new Messenger for the communication back
@@ -118,4 +121,4 @@ public class DeleteFileDialogFragment extends DialogFragment {
return alert.create();
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
index dc40bab2a..3ff88aa2b 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * 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
@@ -28,6 +28,11 @@ 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.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
@@ -41,140 +46,163 @@ import java.util.ArrayList;
public class DeleteKeyDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger";
- private static final String ARG_DELETE_KEY_RING_ROW_IDS = "delete_file";
- private static final String ARG_KEY_TYPE = "key_type";
+ private static final String ARG_DELETE_KEY_RING_ROW_IDS = "delete_key_ring_row_ids";
public static final int MESSAGE_OKAY = 1;
+ public static final int MESSAGE_ERROR = 0;
- public static final String MESSAGE_NOT_DELETED = "not_deleted";
+ private boolean isSingleSelection = false;
+
+ private TextView mainMessage;
+ private CheckBox checkDeleteSecret;
+ private LinearLayout deleteSecretKeyView;
+ private View inflateView;
private Messenger mMessenger;
/**
* Creates new instance of this delete file dialog fragment
*/
- public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] keyRingRowIds,
- int keyType) {
+ public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] keyRingRowIds
+ ) {
DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_MESSENGER, messenger);
args.putLongArray(ARG_DELETE_KEY_RING_ROW_IDS, keyRingRowIds);
- args.putInt(ARG_KEY_TYPE, keyType);
+ //We don't need the key type
frag.setArguments(args);
return frag;
}
- /**
- * Creates dialog
- */
+
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
+
final FragmentActivity activity = getActivity();
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
final long[] keyRingRowIds = getArguments().getLongArray(ARG_DELETE_KEY_RING_ROW_IDS);
- final int keyType = getArguments().getInt(ARG_KEY_TYPE);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+
+ //Setup custom View to display in AlertDialog
+ LayoutInflater inflater = activity.getLayoutInflater();
+ inflateView = inflater.inflate(R.layout.view_key_delete_fragment, null);
+ builder.setView(inflateView);
+
+ deleteSecretKeyView = (LinearLayout) inflateView.findViewById(R.id.deleteSecretKeyView);
+ mainMessage = (TextView) inflateView.findViewById(R.id.mainMessage);
+ checkDeleteSecret = (CheckBox) inflateView.findViewById(R.id.checkDeleteSecret);
+
builder.setTitle(R.string.warning);
+ //If only a single key has been selected
if (keyRingRowIds.length == 1) {
Uri dataUri;
- if (keyType == Id.type.public_key) {
- dataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(String.valueOf(keyRingRowIds[0]));
+ ArrayList<Long> publicKeyRings; //Any one will do
+ isSingleSelection = true;
+
+ long selectedRow = keyRingRowIds[0];
+ long keyType;
+ publicKeyRings = ProviderHelper.getPublicKeyRingsRowIds(activity);
+
+ if (publicKeyRings.contains(selectedRow)) {
+ //TODO Should be a better method to do this other than getting all the KeyRings
+ dataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(String.valueOf(selectedRow));
+ keyType = Id.type.public_key;
} else {
- dataUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowIds[0]));
+ dataUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(String.valueOf(selectedRow));
+ keyType = Id.type.secret_key;
}
+
String userId = ProviderHelper.getUserId(activity, dataUri);
+ //Hide the Checkbox and TextView since this is a single selection,user will be notified thru message
+ deleteSecretKeyView.setVisibility(View.GONE);
+ //Set message depending on which key it is.
+ mainMessage.setText(getString(keyType == Id.type.secret_key ? R.string.secret_key_deletion_confirmation
+ : R.string.public_key_deletetion_confirmation, userId));
+
- builder.setMessage(getString(
- keyType == Id.type.public_key ? R.string.key_deletion_confirmation
- : R.string.secret_key_deletion_confirmation, userId));
} else {
- builder.setMessage(R.string.key_deletion_confirmation_multi);
+ deleteSecretKeyView.setVisibility(View.VISIBLE);
+ mainMessage.setText(R.string.key_deletion_confirmation_multi);
}
+
builder.setIcon(R.drawable.ic_dialog_alert_holo_light);
builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
-
@Override
- public void onClick(DialogInterface dialog, int id) {
- ArrayList<String> notDeleted = new ArrayList<String>();
-
- if (keyType == Id.type.public_key) {
- Uri queryUri = KeychainContract.KeyRings.buildPublicKeyRingsUri();
- String[] projection = new String[]{
- KeychainContract.KeyRings._ID, // 0
- KeychainContract.KeyRings.MASTER_KEY_ID, // 1
- KeychainContract.UserIds.USER_ID // 2
- };
-
- // make selection with all entries where _ID is one of the given row ids
- String selection = KeychainDatabase.Tables.KEY_RINGS + "." +
- KeychainContract.KeyRings._ID + " IN(";
- String selectionIDs = "";
- for (int i = 0; i < keyRingRowIds.length; i++) {
- selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'";
- if (i+1 < keyRingRowIds.length)
- selectionIDs += ",";
- }
- selection += selectionIDs + ")";
-
- Cursor cursor = activity.getContentResolver().query(queryUri, projection,
- selection, null, null);
-
- long rowId;
- long masterKeyId;
- String userId;
- try {
- while (cursor != null && cursor.moveToNext()) {
- rowId = cursor.getLong(0);
- masterKeyId = cursor.getLong(1);
- userId = cursor.getString(2);
-
- Log.d(Constants.TAG, "rowId: " + rowId + ", masterKeyId: " + masterKeyId
- + ", userId: " + userId);
-
- // check if a corresponding secret key exists...
- Cursor secretCursor = activity.getContentResolver().query(
- KeychainContract.KeyRings.buildSecretKeyRingsByMasterKeyIdUri(String.valueOf(masterKeyId)),
- null, null, null, null
- );
- if (secretCursor != null && secretCursor.getCount() > 0) {
- notDeleted.add(userId);
- } else {
- // it is okay to delete this key, no secret key found!
- ProviderHelper.deletePublicKeyRing(activity, rowId);
- }
- if (secretCursor != null) {
- secretCursor.close();
+ public void onClick(DialogInterface dialog, int which) {
+ Uri queryUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri();
+ String[] projection = new String[]{
+ KeychainContract.KeyRings.MASTER_KEY_ID, // 0
+ KeychainContract.KeyRings.TYPE// 1
+ };
+
+ // make selection with all entries where _ID is one of the given row ids
+ String selection = KeychainDatabase.Tables.KEY_RINGS + "." +
+ KeychainContract.KeyRings._ID + " IN(";
+ String selectionIDs = "";
+ for (int i = 0; i < keyRingRowIds.length; i++) {
+ selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'";
+ if (i + 1 < keyRingRowIds.length)
+ selectionIDs += ",";
+ }
+ selection += selectionIDs + ")";
+
+ Cursor cursor = activity.getContentResolver().query(queryUri, projection,
+ selection, null, null);
+
+
+ long masterKeyId;
+ long keyType;
+ boolean isSuccessfullyDeleted;
+ try {
+ isSuccessfullyDeleted = false;
+ while (cursor != null && cursor.moveToNext()) {
+ masterKeyId = cursor.getLong(0);
+ keyType = cursor.getLong(1);
+
+ Log.d(Constants.TAG, "masterKeyId: " + masterKeyId
+ + ", keyType:" + (keyType == KeychainContract.KeyTypes.PUBLIC ? "Public" : "Private"));
+
+
+ if (keyType == KeychainContract.KeyTypes.SECRET) {
+ if (checkDeleteSecret.isChecked() || isSingleSelection) {
+ ProviderHelper.deleteUnifiedKeyRing(activity, String.valueOf(masterKeyId), true);
}
- }
- } finally {
- if (cursor != null) {
- cursor.close();
+ } else {
+ ProviderHelper.deleteUnifiedKeyRing(activity, String.valueOf(masterKeyId), false);
}
}
- } else {
- for (long keyRowId : keyRingRowIds) {
- ProviderHelper.deleteSecretKeyRing(activity, keyRowId);
+
+ //Check if the selected rows have actually been deleted
+ cursor = activity.getContentResolver().query(queryUri, projection, selection, null, null);
+ if (cursor == null || cursor.getCount() == 0 || !checkDeleteSecret.isChecked()) {
+ isSuccessfullyDeleted = true;
+ }
+
+ } finally {
+ if (cursor != null) {
+ cursor.close();
}
+
}
dismiss();
- if (notDeleted.size() > 0) {
- Bundle data = new Bundle();
- data.putStringArrayList(MESSAGE_NOT_DELETED, notDeleted);
- sendMessageToHandler(MESSAGE_OKAY, data);
- } else {
+ if (isSuccessfullyDeleted) {
sendMessageToHandler(MESSAGE_OKAY, null);
+ } else {
+ sendMessageToHandler(MESSAGE_ERROR, null);
}
}
- });
+
+ }
+ );
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
@@ -196,7 +224,6 @@ public class DeleteKeyDialogFragment extends DialogFragment {
if (data != null) {
msg.setData(data);
}
-
try {
mMessenger.send(msg);
} catch (RemoteException e) {
@@ -205,4 +232,5 @@ public class DeleteKeyDialogFragment extends DialogFragment {
Log.w(Constants.TAG, "Messenger is null!", e);
}
}
+
} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
index 39ce63b5f..a4285c8e9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
@@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.FileHelper;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -33,14 +28,16 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.DialogFragment;
-import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.FileHelper;
+import org.sufficientlysecure.keychain.util.Log;
public class FileDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger";
@@ -67,7 +64,7 @@ public class FileDialogFragment extends DialogFragment {
* Creates new instance of this file dialog fragment
*/
public static FileDialogFragment newInstance(Messenger messenger, String title, String message,
- String defaultFile, String checkboxText) {
+ String defaultFile, String checkboxText) {
FileDialogFragment frag = new FileDialogFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_MESSENGER, messenger);
@@ -177,34 +174,33 @@ public class FileDialogFragment extends DialogFragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode & 0xFFFF) {
- case REQUEST_CODE: {
- if (resultCode == Activity.RESULT_OK && data != null) {
- try {
- String path = data.getData().getPath();
- Log.d(Constants.TAG, "path=" + path);
-
- // set filename used in export/import dialogs
- setFilename(path);
- } catch (NullPointerException e) {
- Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
+ case REQUEST_CODE: {
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ try {
+ String path = data.getData().getPath();
+ Log.d(Constants.TAG, "path=" + path);
+
+ // set filename used in export/import dialogs
+ setFilename(path);
+ } catch (NullPointerException e) {
+ Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
+ }
}
- }
- break;
- }
+ break;
+ }
- default:
- super.onActivityResult(requestCode, resultCode, data);
+ default:
+ super.onActivityResult(requestCode, resultCode, data);
- break;
+ break;
}
}
/**
* Send message back to handler which is initialized in a activity
- *
- * @param what
- * Message integer you want to send
+ *
+ * @param what Message integer you want to send
*/
private void sendMessageToHandler(Integer what, Bundle data) {
Message msg = Message.obtain();
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
index c00232fd1..271219fa3 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
@@ -17,20 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -52,6 +38,19 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPPrivateKey;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.util.Log;
public class PassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger";
@@ -62,20 +61,18 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
private Messenger mMessenger;
private EditText mPassphraseEditText;
- private boolean canKB;
+ private boolean mCanKB;
/**
* Creates new instance of this dialog fragment
- *
- * @param secretKeyId
- * secret key id you want to use
- * @param messenger
- * to communicate back after caching the passphrase
+ *
+ * @param secretKeyId secret key id you want to use
+ * @param messenger to communicate back after caching the passphrase
* @return
* @throws PgpGeneralException
*/
public static PassphraseDialogFragment newInstance(Context context, Messenger messenger,
- long secretKeyId) throws PgpGeneralException {
+ long secretKeyId) throws PgpGeneralException {
// check if secret key has a passphrase
if (!(secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none)) {
if (!PassphraseCacheService.hasPassphrase(context, secretKeyId)) {
@@ -131,7 +128,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
}
});
alert.setCancelable(false);
- canKB = false;
+ mCanKB = false;
return alert.create();
}
String userId = PgpKeyHelper.getMainUserIdSafe(activity, secretKey);
@@ -158,7 +155,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
PGPSecretKey clickSecretKey = secretKey;
if (clickSecretKey != null) {
- while (keyOK == true) {
+ while (keyOK) {
if (clickSecretKey != null) { // check again for loop
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
@@ -171,7 +168,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
Toast.makeText(activity,
R.string.error_could_not_extract_private_key,
Toast.LENGTH_SHORT).show();
-
+
sendMessageToHandler(MESSAGE_CANCEL);
return;
} else {
@@ -187,14 +184,14 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} catch (PGPException e) {
Toast.makeText(activity, R.string.wrong_passphrase,
Toast.LENGTH_SHORT).show();
-
+
sendMessageToHandler(MESSAGE_CANCEL);
return;
}
} else {
Toast.makeText(activity, R.string.error_could_not_extract_private_key,
Toast.LENGTH_SHORT).show();
-
+
sendMessageToHandler(MESSAGE_CANCEL);
return; // ran out of keys to try
}
@@ -207,7 +204,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
// cache the new passphrase
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase);
- if (keyOK == false && clickSecretKey.getKeyID() != keyId) {
+ if (!keyOK && clickSecretKey.getKeyID() != keyId) {
PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(),
passphrase);
}
@@ -224,14 +221,14 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
}
});
- canKB = true;
+ mCanKB = true;
return alert.create();
}
@Override
public void onActivityCreated(Bundle arg0) {
super.onActivityCreated(arg0);
- if (canKB) {
+ if (mCanKB) {
// request focus and open soft keyboard
mPassphraseEditText.requestFocus();
getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
@@ -265,9 +262,8 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
/**
* Send message back to handler which is initialized in a activity
- *
- * @param what
- * Message integer you want to send
+ *
+ * @param what Message integer you want to send
*/
private void sendMessageToHandler(Integer what) {
Message msg = Message.obtain();
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
index 6c62d14e0..132a2ce86 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
@@ -26,11 +26,10 @@ import android.content.DialogInterface.OnKeyListener;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.KeyEvent;
-
import org.sufficientlysecure.keychain.R;
public class ProgressDialogFragment extends DialogFragment {
- private static final String ARG_MESSAGE_ID = "message_id";
+ private static final String ARG_MESSAGE = "message";
private static final String ARG_STYLE = "style";
private static final String ARG_CANCELABLE = "cancelable";
@@ -39,16 +38,16 @@ public class ProgressDialogFragment extends DialogFragment {
/**
* Creates new instance of this fragment
*
- * @param messageId
+ * @param message
* @param style
* @param cancelable
* @return
*/
- public static ProgressDialogFragment newInstance(int messageId, int style, boolean cancelable,
+ public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable,
OnCancelListener onCancelListener) {
ProgressDialogFragment frag = new ProgressDialogFragment();
Bundle args = new Bundle();
- args.putInt(ARG_MESSAGE_ID, messageId);
+ args.putString(ARG_MESSAGE, message);
args.putInt(ARG_STYLE, style);
args.putBoolean(ARG_CANCELABLE, cancelable);
@@ -101,8 +100,9 @@ public class ProgressDialogFragment extends DialogFragment {
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
- if (this.mOnCancelListener != null)
+ if (this.mOnCancelListener != null) {
this.mOnCancelListener.onCancel(dialog);
+ }
}
/**
@@ -117,22 +117,22 @@ public class ProgressDialogFragment extends DialogFragment {
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
- int messageId = getArguments().getInt(ARG_MESSAGE_ID);
+ String message = getArguments().getString(ARG_MESSAGE);
int style = getArguments().getInt(ARG_STYLE);
boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE);
- dialog.setMessage(getString(messageId));
+ dialog.setMessage(message);
dialog.setProgressStyle(style);
if (cancelable) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE,
activity.getString(R.string.progress_cancel),
new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
}
// Disable the back button
@@ -140,7 +140,6 @@ public class ProgressDialogFragment extends DialogFragment {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
-
if (keyCode == KeyEvent.KEYCODE_BACK) {
return true;
}
@@ -152,4 +151,4 @@ public class ProgressDialogFragment extends DialogFragment {
return dialog;
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
index e406547b3..ae61c1470 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
@@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.Log;
-
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -40,6 +36,9 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger";
@@ -55,11 +54,9 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
/**
* Creates new instance of this dialog fragment
- *
- * @param title
- * title of dialog
- * @param messenger
- * to communicate back after setting the passphrase
+ *
+ * @param title title of dialog
+ * @param messenger to communicate back after setting the passphrase
* @return
*/
public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) {
@@ -96,7 +93,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-
+
@Override
public void onClick(DialogInterface dialog, int id) {
dismiss();
@@ -130,7 +127,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
});
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-
+
@Override
public void onClick(DialogInterface dialog, int id) {
dismiss();
@@ -168,9 +165,8 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
/**
* Send message back to handler which is initialized in a activity
- *
- * @param what
- * Message integer you want to send
+ *
+ * @param what Message integer you want to send
*/
private void sendMessageToHandler(Integer what, Bundle data) {
Message msg = Message.obtain();
@@ -187,4 +183,4 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
Log.w(Constants.TAG, "Messenger is null!", e);
}
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java
index b850638a6..741530b1d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java
@@ -17,9 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog;
-import org.sufficientlysecure.htmltextview.HtmlTextView;
-import org.sufficientlysecure.keychain.R;
-
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -31,6 +28,8 @@ import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
+import org.sufficientlysecure.htmltextview.HtmlTextView;
+import org.sufficientlysecure.keychain.R;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class ShareNfcDialogFragment extends DialogFragment {
@@ -97,4 +96,4 @@ public class ShareNfcDialogFragment extends DialogFragment {
return alert.create();
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
index f26cd35c0..94586810e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
@@ -28,7 +28,6 @@ import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
@@ -91,7 +90,7 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
alert.setPositiveButton(R.string.btn_okay, null);
byte[] fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), dataUri);
- String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, false);
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java
index b9dcd0d25..da29f808a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java
@@ -24,7 +24,7 @@ import android.widget.ListView;
/**
* Automatically calculate height of ListView based on contained items. This enables to put this
* ListView into a ScrollView without messing up.
- *
+ * <p/>
* from
* http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview-
* or-has-the-scrollview-dis
@@ -52,4 +52,4 @@ public class FixedListView extends ListView {
super.onMeasure(widthMeasureSpec, expandSpec);
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java
new file mode 100644
index 000000000..f9a5b92f3
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java
@@ -0,0 +1,203 @@
+/*
+ * 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.ui.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.beardedhen.androidbootstrap.FontAwesomeText;
+import org.sufficientlysecure.keychain.R;
+
+/**
+ * Class representing a LinearLayout that can fold and hide it's content when pressed
+ * To use just add the following to your xml layout
+
+ <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ custom:foldedLabel="@string/TEXT_TO_DISPLAY_WHEN_FOLDED"
+ custom:unFoldedLabel="@string/TEXT_TO_DISPLAY_WHEN_UNFOLDED"
+ custom:foldedIcon="ICON_NAME_FROM_FontAwesomeText_TO_USE_WHEN_FOLDED"
+ custom:unFoldedIcon="ICON_NAME_FROM_FontAwesomeText_TO_USE_WHEN_UNFOLDED">
+
+ <include layout="@layout/ELEMENTS_TO_BE_FOLDED"/>
+
+ </org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout>
+
+ */
+public class FoldableLinearLayout extends LinearLayout {
+
+ private FontAwesomeText mFoldableIcon;
+ private boolean mFolded;
+ private boolean mHasMigrated = false;
+ private Integer mShortAnimationDuration = null;
+ private TextView mFoldableTextView = null;
+ private LinearLayout mFoldableContainer = null;
+ private View mFoldableLayout = null;
+
+ private String mFoldedIconName;
+ private String mUnFoldedIconName;
+ private String mFoldedLabel;
+ private String mUnFoldedLabel;
+
+ public FoldableLinearLayout(Context context) {
+ super(context);
+ processAttributes(context, null);
+ }
+
+ public FoldableLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ processAttributes(context, attrs);
+ }
+
+ public FoldableLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+ processAttributes(context, attrs);
+ }
+
+ /**
+ * Load given attributes to inner variables,
+ * @param context
+ * @param attrs
+ */
+ private void processAttributes(Context context, AttributeSet attrs) {
+ if(attrs != null) {
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.FoldableLinearLayout, 0, 0);
+ mFoldedIconName = a.getString(R.styleable.FoldableLinearLayout_foldedIcon);
+ mUnFoldedIconName = a.getString(R.styleable.FoldableLinearLayout_unFoldedIcon);
+ mFoldedLabel = a.getString(R.styleable.FoldableLinearLayout_foldedLabel);
+ mUnFoldedLabel = a.getString(R.styleable.FoldableLinearLayout_unFoldedLabel);
+ a.recycle();
+ }
+ // If any attribute isn't found then set a default one
+ mFoldedIconName = (mFoldedIconName == null) ? "fa-chevron-right" : mFoldedIconName;
+ mUnFoldedIconName = (mUnFoldedIconName == null) ? "fa-chevron-down" : mUnFoldedIconName;
+ mFoldedLabel = (mFoldedLabel == null) ? context.getString(R.id.none) : mFoldedLabel;
+ mUnFoldedLabel = (mUnFoldedLabel == null) ? context.getString(R.id.none) : mUnFoldedLabel;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ // if the migration has already happened
+ // there is no need to move any children
+ if(!mHasMigrated) {
+ migrateChildrenToContainer();
+ mHasMigrated = true;
+ }
+
+ initialiseInnerViews();
+
+ super.onFinishInflate();
+ }
+
+ /**
+ * Migrates Child views as declared in xml to the inner foldableContainer
+ */
+ private void migrateChildrenToContainer() {
+ // Collect children of FoldableLinearLayout as declared in XML
+ int childNum = getChildCount();
+ View[] children = new View[childNum];
+
+ for(int i = 0; i < childNum; i++) {
+ children[i] = getChildAt(i);
+ }
+ if(children[0].getId() == R.id.foldableControl) {
+
+ }
+
+ // remove all of them from FoldableLinearLayout
+ detachAllViewsFromParent();
+
+ // Inflate the inner foldable_linearlayout.xml
+ LayoutInflater inflator = (LayoutInflater)getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ mFoldableLayout = inflator.inflate(R.layout.foldable_linearlayout, this, true);
+ mFoldableContainer = (LinearLayout) mFoldableLayout.findViewById(R.id.foldableContainer);
+
+ // Push previously collected children into foldableContainer.
+ for(int i = 0; i < childNum; i++) {
+ addView(children[i]);
+ }
+ }
+
+ private void initialiseInnerViews() {
+ mFoldableIcon = (FontAwesomeText) mFoldableLayout.findViewById(R.id.foldableIcon);
+ mFoldableIcon.setIcon(mFoldedIconName);
+ mFoldableTextView = (TextView) mFoldableLayout.findViewById(R.id.foldableText);
+ mFoldableTextView.setText(mFoldedLabel);
+
+ // retrieve and cache the system's short animation time
+ mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
+
+ LinearLayout foldableControl = (LinearLayout) mFoldableLayout.findViewById(R.id.foldableControl);
+ foldableControl.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mFolded = !mFolded;
+ if (mFolded) {
+ mFoldableIcon.setIcon(mUnFoldedIconName);
+ mFoldableContainer.setVisibility(View.VISIBLE);
+ AlphaAnimation animation = new AlphaAnimation(0f, 1f);
+ animation.setDuration(mShortAnimationDuration);
+ mFoldableContainer.startAnimation(animation);
+ mFoldableTextView.setText(mUnFoldedLabel);
+
+ } else {
+ mFoldableIcon.setIcon(mFoldedIconName);
+ AlphaAnimation animation = new AlphaAnimation(1f, 0f);
+ animation.setDuration(mShortAnimationDuration);
+ animation.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) { }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ // making sure that at the end the container is completely removed from view
+ mFoldableContainer.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) { }
+ });
+ mFoldableContainer.startAnimation(animation);
+ mFoldableTextView.setText(mFoldedLabel);
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Adds provided child view to foldableContainer View
+ * @param child
+ */
+ @Override
+ public void addView(View child) {
+ if(mFoldableContainer != null) {
+ mFoldableContainer.addView(child);
+ }
+ }
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java
index bc60b2adf..6e1e4c678 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java
@@ -25,7 +25,7 @@ import android.util.AttributeSet;
* values should use {@link android.content.SharedPreferences#getInt}. When using XML-declared
* arrays for entry values, the arrays should be regular string arrays containing valid integer
* values.
- *
+ *
* @author Rodrigo Damazio
*/
public class IntegerListPreference extends ListPreference {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java
index b1f97babf..0dfc6dc5e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java
@@ -30,7 +30,7 @@ import org.spongycastle.openpgp.PGPSecretKey;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.Choice;
-
+import android.annotation.TargetApi;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.Context;
@@ -47,8 +47,16 @@ import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.sufficientlysecure.keychain.Id;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.util.Choice;
+
+import java.text.DateFormat;
+import java.util.*;
public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
private PGPSecretKey mKey;
@@ -85,7 +93,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
private int mDatePickerResultCount = 0;
- private DatePickerDialog.OnDateSetListener mExpiryDateSetListener = new DatePickerDialog.OnDateSetListener() {
+ private DatePickerDialog.OnDateSetListener mExpiryDateSetListener =
+ new DatePickerDialog.OnDateSetListener() {
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
// Note: Ignore results after the first one - android sends multiples.
if (mDatePickerResultCount++ == 0) {
@@ -139,6 +148,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
setExpiryDate(null);
mExpiryDateButton.setOnClickListener(new OnClickListener() {
+ @TargetApi(11)
public void onClick(View v) {
GregorianCalendar date = mExpiryDate;
if (date == null) {
@@ -169,16 +179,18 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
});
// setCalendarViewShown() is supported from API 11 onwards.
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB)
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
// Hide calendarView in tablets because of the unix warparound bug.
dialog.getDatePicker().setCalendarViewShown(false);
-
+ }
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- if ( dialog != null && mCreatedDate != null ) {
- dialog.getDatePicker().setMinDate(mCreatedDate.getTime().getTime()+ DateUtils.DAY_IN_MILLIS);
+ if (dialog != null && mCreatedDate != null) {
+ dialog.getDatePicker()
+ .setMinDate(
+ mCreatedDate.getTime().getTime() + DateUtils.DAY_IN_MILLIS);
} else {
//When created date isn't available
- dialog.getDatePicker().setMinDate(date.getTime().getTime()+ DateUtils.DAY_IN_MILLIS);
+ dialog.getDatePicker().setMinDate(date.getTime().getTime() + DateUtils.DAY_IN_MILLIS);
}
}
@@ -208,9 +220,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
}
mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(key));
- String keyId1Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID());
- String keyId2Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID() >> 32);
- mKeyId.setText(keyId1Str + " " + keyId2Str);
+ String keyIdStr = PgpKeyHelper.convertKeyIdToHex(key.getKeyID());
+ mKeyId.setText(keyIdStr);
Vector<Choice> choices = new Vector<Choice>();
boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT);
@@ -353,9 +364,11 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
class ExpiryDatePickerDialog extends DatePickerDialog {
- public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) {
+ public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack,
+ int year, int monthOfYear, int dayOfMonth) {
super(context, callBack, year, monthOfYear, dayOfMonth);
}
+
//Set permanent title.
public void setTitle(CharSequence title) {
super.setTitle(getContext().getString(R.string.expiry_date_dialog_title));
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java
index 47238cd56..171763672 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java
@@ -16,8 +16,6 @@
package org.sufficientlysecure.keychain.ui.widget;
-import org.sufficientlysecure.keychain.R;
-
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
@@ -25,8 +23,8 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.R;
public class KeyServerEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java
index 9758835d2..6c7737e6d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java
@@ -48,9 +48,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
-
import com.beardedhen.androidbootstrap.BootstrapButton;
-
import org.spongycastle.openpgp.PGPSecretKey;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
@@ -75,10 +73,10 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
private Choice mNewKeyAlgorithmChoice;
private int mNewKeySize;
- private boolean canEdit = true;
private boolean oldItemDeleted = false;
private ArrayList<String> mDeletedIDs = new ArrayList<String>();
private ArrayList<PGPSecretKey> mDeletedKeys = new ArrayList<PGPSecretKey>();
+ private boolean mCanEdit = true;
private ActionBarActivity mActivity;
@@ -105,30 +103,32 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
public void setType(int type) {
mType = type;
switch (type) {
- case Id.type.user_id: {
- mTitle.setText(R.string.section_user_ids);
- break;
- }
+ case Id.type.user_id: {
+ mTitle.setText(R.string.section_user_ids);
+ break;
+ }
- case Id.type.key: {
- mTitle.setText(R.string.section_keys);
- break;
- }
+ case Id.type.key: {
+ mTitle.setText(R.string.section_keys);
+ break;
+ }
- default: {
- break;
- }
+ default: {
+ break;
+ }
}
}
public void setCanEdit(boolean bCanEdit) {
- canEdit = bCanEdit;
- if (!canEdit) {
+ mCanEdit = bCanEdit;
+ if (!mCanEdit) {
mPlusButton.setVisibility(View.INVISIBLE);
}
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
@Override
protected void onFinishInflate() {
mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -146,7 +146,9 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
super.onFinishInflate();
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
public void onDeleted(Editor editor, boolean wasNewItem) {
oldItemDeleted |= !wasNewItem;
if (oldItemDeleted) {
@@ -262,39 +264,44 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
return mList;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
public void onClick(View v) {
- if (canEdit) {
+ if (mCanEdit) {
switch (mType) {
- case Id.type.user_id: {
- UserIdEditor view = (UserIdEditor) mInflater.inflate(
- R.layout.edit_key_user_id_item, mEditors, false);
- view.setEditorListener(this);
- view.setValue("", mEditors.getChildCount() == 0, true);
- mEditors.addView(view);
- if (mEditorListener != null) {
- mEditorListener.onEdited();
+ case Id.type.user_id: {
+ UserIdEditor view = (UserIdEditor) mInflater.inflate(
+ R.layout.edit_key_user_id_item, mEditors, false);
+ view.setEditorListener(this);
+ view.setValue("", mEditors.getChildCount() == 0, true);
+ mEditors.addView(view);
+ if (mEditorListener != null) {
+ mEditorListener.onEdited();
+ }
+ break;
}
- break;
- }
- case Id.type.key: {
- CreateKeyDialogFragment mCreateKeyDialogFragment = CreateKeyDialogFragment.newInstance(mEditors.getChildCount());
- mCreateKeyDialogFragment.setOnAlgorithmSelectedListener(new CreateKeyDialogFragment.OnAlgorithmSelectedListener() {
- @Override
- public void onAlgorithmSelected(Choice algorithmChoice, int keySize) {
- mNewKeyAlgorithmChoice = algorithmChoice;
- mNewKeySize = keySize;
- createKey();
- }
- });
- mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog");
- break;
- }
+ case Id.type.key: {
+ CreateKeyDialogFragment mCreateKeyDialogFragment =
+ CreateKeyDialogFragment.newInstance(mEditors.getChildCount());
+ mCreateKeyDialogFragment
+ .setOnAlgorithmSelectedListener(
+ new CreateKeyDialogFragment.OnAlgorithmSelectedListener() {
+ @Override
+ public void onAlgorithmSelected(Choice algorithmChoice, int keySize) {
+ mNewKeyAlgorithmChoice = algorithmChoice;
+ mNewKeySize = keySize;
+ createKey();
+ }
+ });
+ mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog");
+ break;
+ }
- default: {
- break;
- }
+ default: {
+ break;
+ }
}
this.updateEditorsVisible();
}
@@ -311,7 +318,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
mEditors, false);
view.setEditorListener(this);
view.setValue(userId, mEditors.getChildCount() == 0, false);
- view.setCanEdit(canEdit);
+ view.setCanEdit(mCanEdit);
mEditors.addView(view);
}
@@ -332,7 +339,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
view.setEditorListener(this);
boolean isMasterKey = (mEditors.getChildCount() == 0);
view.setValue(list.get(i), isMasterKey, usages.get(i), newKeys);
- view.setCanEdit(canEdit);
+ view.setCanEdit(mCanEdit);
mEditors.addView(view);
}
@@ -367,19 +374,22 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// show progress dialog
- mGeneratingDialog = ProgressDialogFragment.newInstance(R.string.progress_generating,
- ProgressDialog.STYLE_SPINNER, true, new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- mActivity.stopService(intent);
- }
- });
+ mGeneratingDialog = ProgressDialogFragment.newInstance(
+ getResources().getQuantityString(R.plurals.progress_generating, 1),
+ ProgressDialog.STYLE_SPINNER,
+ true,
+ new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ mActivity.stopService(intent);
+ }
+ });
- // Message is received after generating is done in ApgService
+ // Message is received after generating is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity,
mGeneratingDialog) {
public void handleMessage(Message message) {
- // handle messages by standard ApgHandler first
+ // handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
@@ -390,7 +400,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
.getByteArray(KeychainIntentService.RESULT_NEW_KEY));
addGeneratedKeyToView(newKey);
}
- };
+ }
};
// Create a new Messenger for the communication back
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java
index 752d44f89..937a48e48 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java
@@ -26,7 +26,7 @@ import android.widget.TextView;
/**
* Copied from StickyListHeaders lib example
- *
+ *
* @author Eric Frohnhoefer
*/
public class UnderlineTextView extends TextView {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java
index 8760b72f7..d4b15613a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java
@@ -21,19 +21,18 @@ import java.util.regex.Pattern;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
+import android.util.Patterns;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.RadioButton;
-
+import android.widget.*;
import com.beardedhen.androidbootstrap.BootstrapButton;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
+
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null;
@@ -43,21 +42,13 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
private String mOriginalID;
private EditText mName;
private String mOriginalName;
- private EditText mEmail;
+ private AutoCompleteTextView mEmail;
private String mOriginalEmail;
private EditText mComment;
private String mOriginalComment;
private boolean mOriginallyMainUserID;
private boolean mIsNewId;
- // see http://www.regular-expressions.info/email.html
- // RFC 2822 if we omit the syntax using double quotes and square brackets
- // android.util.Patterns.EMAIL_ADDRESS is only available as of Android 2.2+
- private static final Pattern EMAIL_PATTERN = Pattern
- .compile(
- "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
- Pattern.CASE_INSENSITIVE);
-
public void setCanEdit(boolean bCanEdit) {
if (!bCanEdit) {
mDeleteButton.setVisibility(View.INVISIBLE);
@@ -114,11 +105,46 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
mName = (EditText) findViewById(R.id.name);
mName.addTextChangedListener(mTextWatcher);
- mEmail = (EditText) findViewById(R.id.email);
- mEmail.addTextChangedListener(mTextWatcher);
+ mEmail = (AutoCompleteTextView) findViewById(R.id.email);
mComment = (EditText) findViewById(R.id.comment);
mComment.addTextChangedListener(mTextWatcher);
+
+ mEmail.setThreshold(1); // Start working from first character
+ mEmail.setAdapter(
+ new ArrayAdapter<String>
+ (this.getContext(), android.R.layout.simple_dropdown_item_1line,
+ ContactHelper.getMailAccounts(getContext())
+ ));
+ mEmail.addTextChangedListener(new TextWatcher(){
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ String email = editable.toString();
+ if (email.length() > 0) {
+ Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
+ if (emailMatcher.matches()) {
+ mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ android.R.drawable.presence_online, 0);
+ } else {
+ mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ android.R.drawable.presence_offline, 0);
+ }
+ } else {
+ // remove drawable if email is empty
+ mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+ }
+ if (mEditorListener != null) {
+ mEditorListener.onEdited();
+ }
+ }
+ });
+
super.onFinishInflate();
}
@@ -151,19 +177,11 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
setIsMainUserId(isMainID);
}
- public String getValue() throws InvalidEmailException {
+ public String getValue() {
String name = ("" + mName.getText()).trim();
String email = ("" + mEmail.getText()).trim();
String comment = ("" + mComment.getText()).trim();
- if (email.length() > 0) {
- Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
- if (!emailMatcher.matches()) {
- throw new InvalidEmailException(getContext().getString(R.string.error_invalid_email,
- email));
- }
- }
-
String userId = name;
if (comment.length() > 0) {
userId += " (" + comment + ")";
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
index d3c37edc6..d2f4cc003 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java
@@ -17,13 +17,14 @@
package org.sufficientlysecure.keychain.util;
-import java.util.HashMap;
+import android.annotation.SuppressLint;
+import android.app.Activity;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
-import android.annotation.SuppressLint;
-import android.app.Activity;
+
+import java.util.HashMap;
@SuppressLint("UseSparseArrays")
public class AlgorithmNames {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java
index 9e0042c00..1a6184d9c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java
@@ -39,7 +39,7 @@ public class Choice {
}
@Override
- public String toString() {
+ public String toString() {
return mName;
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java
index 921d22f21..b987e1533 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java
@@ -18,24 +18,6 @@
package org.sufficientlysecure.keychain.util;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.Locale;
-
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
@@ -47,19 +29,22 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
-import android.text.Html;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.*;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry.getAlgorithmFromId;
-/**
- * TODO:
- * rewrite to use machine readable output.
- * <p/>
- * see http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5
- * https://github.com/openpgp-keychain/openpgp-keychain/issues/259
- */
public class HkpKeyServer extends KeyServer {
private static class HttpError extends Exception {
private static final long serialVersionUID = 1718783705229428893L;
@@ -82,21 +67,86 @@ public class HkpKeyServer extends KeyServer {
}
private String mHost;
- private short mPort = 11371;
-
- // example:
- // pub 2048R/<a href="/pks/lookup?op=get&search=0x887DF4BE9F5C9090">9F5C9090</a> 2009-08-17 <a
- // href="/pks/lookup?op=vindex&search=0x887DF4BE9F5C9090">Jörg Runge
- // &lt;joerg@joergrunge.de&gt;</a>
- public static Pattern PUB_KEY_LINE = Pattern
- .compile(
- "pub +([0-9]+)([a-z]+)/.*?0x([0-9a-z]+).*? +([0-9-]+) +(.+)[\n\r]+((?: +.+[\n\r]+)*)",
+ private short mPort;
+
+ /**
+ * pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags%
+ * <ul>
+ * <li>%<b>keyid</b>% = this is either the fingerprint or the key ID of the key. Either the 16-digit or 8-digit
+ * key IDs are acceptable, but obviously the fingerprint is best.</li>
+ * <li>%<b>algo</b>% = the algorithm number, (i.e. 1==RSA, 17==DSA, etc).
+ * See <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a></li>
+ * <li>%<b>keylen</b>% = the key length (i.e. 1024, 2048, 4096, etc.)</li>
+ * <li>%<b>creationdate</b>% = creation date of the key in standard
+ * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
+ * 1/1/1970 UTC time)</li>
+ * <li>%<b>expirationdate</b>% = expiration date of the key in standard
+ * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
+ * 1/1/1970 UTC time)</li>
+ * <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any order. The
+ * meaning of "disabled" is implementation-specific. Note that individual flags may be unimplemented, so
+ * the absence of a given flag does not necessarily mean the absence of the detail.
+ * <ul>
+ * <li>r == revoked</li>
+ * <li>d == disabled</li>
+ * <li>e == expired</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * @see <a href="http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2">5.2. Machine Readable Indexes</a>
+ * in Internet-Draft OpenPGP HTTP Keyserver Protocol Document
+ */
+ public static final Pattern PUB_KEY_LINE = Pattern
+ .compile("pub:([0-9a-fA-F]+):([0-9]+):([0-9]+):([0-9]+):([0-9]*):([rde]*)[ \n\r]*" // pub line
+ + "(uid:(.*):([0-9]+):([0-9]*):([rde]*))+", // one or more uid lines
Pattern.CASE_INSENSITIVE);
- public static Pattern USER_ID_LINE = Pattern.compile("^ +(.+)$", Pattern.MULTILINE
- | Pattern.CASE_INSENSITIVE);
- public HkpKeyServer(String host) {
+ /**
+ * uid:%escaped uid string%:%creationdate%:%expirationdate%:%flags%
+ * <ul>
+ * <li>%<b>escaped uid string</b>% = the user ID string, with HTTP %-escaping for anything that isn't 7-bit
+ * safe as well as for the ":" character. Any other characters may be escaped, as desired.</li>
+ * <li>%<b>creationdate</b>% = creation date of the key in standard
+ * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
+ * 1/1/1970 UTC time)</li>
+ * <li>%<b>expirationdate</b>% = expiration date of the key in standard
+ * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of seconds since
+ * 1/1/1970 UTC time)</li>
+ * <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any order. The
+ * meaning of "disabled" is implementation-specific. Note that individual flags may be unimplemented, so
+ * the absence of a given flag does not necessarily mean the absence of the detail.
+ * <ul>
+ * <li>r == revoked</li>
+ * <li>d == disabled</li>
+ * <li>e == expired</li>
+ * </ul>
+ * </li>
+ * </ul>
+ */
+ public static final Pattern UID_LINE = Pattern
+ .compile("uid:(.*):([0-9]+):([0-9]*):([rde]*)",
+ Pattern.CASE_INSENSITIVE);
+
+ private static final short PORT_DEFAULT = 11371;
+
+ /**
+ * @param hostAndPort may be just
+ * "<code>hostname</code>" (eg. "<code>pool.sks-keyservers.net</code>"), then it will
+ * connect using {@link #PORT_DEFAULT}. However, port may be specified after colon
+ * ("<code>hostname:port</code>", eg. "<code>p80.pool.sks-keyservers.net:80</code>").
+ */
+ public HkpKeyServer(String hostAndPort) {
+ String host = hostAndPort;
+ short port = PORT_DEFAULT;
+ final int colonPosition = hostAndPort.lastIndexOf(':');
+ if (colonPosition > 0) {
+ host = hostAndPort.substring(0, colonPosition);
+ final String portStr = hostAndPort.substring(colonPosition + 1);
+ port = Short.decode(portStr);
+ }
mHost = host;
+ mPort = port;
}
public HkpKeyServer(String host, short port) {
@@ -104,7 +154,7 @@ public class HkpKeyServer extends KeyServer {
mPort = port;
}
- static private String readAll(InputStream in, String encoding) throws IOException {
+ private static String readAll(InputStream in, String encoding) throws IOException {
ByteArrayOutputStream raw = new ByteArrayOutputStream();
byte buffer[] = new byte[1 << 16];
@@ -129,6 +179,7 @@ public class HkpKeyServer extends KeyServer {
for (int i = 0; i < ips.length; ++i) {
try {
String url = "http://" + ips[i].getHostAddress() + ":" + mPort + request;
+ Log.d(Constants.TAG, "hkp keyserver query: " + url);
URL realUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
conn.setConnectTimeout(5000);
@@ -166,9 +217,9 @@ public class HkpKeyServer extends KeyServer {
} catch (UnsupportedEncodingException e) {
return null;
}
- String request = "/pks/lookup?op=index&search=" + encodedQuery;
+ String request = "/pks/lookup?op=index&options=mr&search=" + encodedQuery;
- String data = null;
+ String data;
try {
data = query(request);
} catch (HttpError e) {
@@ -186,48 +237,65 @@ public class HkpKeyServer extends KeyServer {
throw new QueryException("querying server(s) for '" + mHost + "' failed");
}
- Matcher matcher = PUB_KEY_LINE.matcher(data);
+ final Matcher matcher = PUB_KEY_LINE.matcher(data);
while (matcher.find()) {
- ImportKeysListEntry info = new ImportKeysListEntry();
- info.bitStrength = Integer.parseInt(matcher.group(1));
- info.algorithm = matcher.group(2);
- info.hexKeyId = "0x" + matcher.group(3);
- info.keyId = PgpKeyHelper.convertHexToKeyId(matcher.group(3));
- String chunks[] = matcher.group(4).split("-");
-
- GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
- tmpGreg.set(Integer.parseInt(chunks[0]), Integer.parseInt(chunks[1]),
- Integer.parseInt(chunks[2]));
- info.date = tmpGreg.getTime();
- info.userIds = new ArrayList<String>();
- if (matcher.group(5).startsWith("*** KEY")) {
- info.revoked = true;
+ final ImportKeysListEntry entry = new ImportKeysListEntry();
+
+ entry.setBitStrength(Integer.parseInt(matcher.group(3)));
+
+ final int algorithmId = Integer.decode(matcher.group(2));
+ entry.setAlgorithm(getAlgorithmFromId(algorithmId));
+
+ // group 1 contains the full fingerprint (v4) or the long key id if available
+ // see https://bitbucket.org/skskeyserver/sks-keyserver/pull-request/12/fixes-for-machine-readable-indexes/diff
+ // and https://github.com/openpgp-keychain/openpgp-keychain/issues/259#issuecomment-38168176
+ String fingerprintOrKeyId = matcher.group(1);
+ if (fingerprintOrKeyId.length() > 16) {
+ entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US));
+ entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length()
+ - 16, fingerprintOrKeyId.length()));
} else {
- String tmp = matcher.group(5).replaceAll("<.*?>", "");
- tmp = Html.fromHtml(tmp).toString();
- info.userIds.add(tmp);
+ // set key id only
+ entry.setKeyIdHex("0x" + fingerprintOrKeyId);
}
- if (matcher.group(6).length() > 0) {
- Matcher matcher2 = USER_ID_LINE.matcher(matcher.group(6));
- while (matcher2.find()) {
- String tmp = matcher2.group(1).replaceAll("<.*?>", "");
- tmp = Html.fromHtml(tmp).toString();
- info.userIds.add(tmp);
+
+ final long creationDate = Long.parseLong(matcher.group(4));
+ final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+ tmpGreg.setTimeInMillis(creationDate * 1000);
+ entry.setDate(tmpGreg.getTime());
+
+ entry.setRevoked(matcher.group(6).contains("r"));
+
+ ArrayList<String> userIds = new ArrayList<String>();
+ final String uidLines = matcher.group(7);
+ final Matcher uidMatcher = UID_LINE.matcher(uidLines);
+ while (uidMatcher.find()) {
+ String tmp = uidMatcher.group(1).trim();
+ if (tmp.contains("%")) {
+ try {
+ // converts Strings like "Universit%C3%A4t" to a proper encoding form "Universität".
+ tmp = (URLDecoder.decode(tmp, "UTF8"));
+ } catch (UnsupportedEncodingException ignored) {
+ // will never happen, because "UTF8" is supported
+ }
}
+ userIds.add(tmp);
}
- results.add(info);
- }
+ entry.setUserIds(userIds);
+ results.add(entry);
+ }
return results;
}
@Override
- public String get(long keyId) throws QueryException {
+ public String get(String keyIdHex) throws QueryException {
HttpClient client = new DefaultHttpClient();
try {
- HttpGet get = new HttpGet("http://" + mHost + ":" + mPort
- + "/pks/lookup?op=get&search=0x" + PgpKeyHelper.convertKeyToHex(keyId));
-
+ String query = "http://" + mHost + ":" + mPort +
+ "/pks/lookup?op=get&options=mr&search=" + keyIdHex;
+ Log.d(Constants.TAG, "hkp keyserver get: " + query);
+ HttpGet get = new HttpGet(query);
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new QueryException("not found");
@@ -250,13 +318,14 @@ public class HkpKeyServer extends KeyServer {
}
@Override
- public void add(String armoredText) throws AddKeyException {
+ public void add(String armoredKey) throws AddKeyException {
HttpClient client = new DefaultHttpClient();
try {
- HttpPost post = new HttpPost("http://" + mHost + ":" + mPort + "/pks/add");
-
+ String query = "http://" + mHost + ":" + mPort + "/pks/add";
+ HttpPost post = new HttpPost(query);
+ Log.d(Constants.TAG, "hkp keyserver add: " + query);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
- nameValuePairs.add(new BasicNameValuePair("keytext", armoredText));
+ nameValuePairs.add(new BasicNameValuePair("keytext", armoredKey));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java
index a43c03e3e..b95b3ee6a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java
@@ -18,30 +18,28 @@ package org.sufficientlysecure.keychain.util;
import android.content.Intent;
import android.support.v4.app.Fragment;
-
import com.google.zxing.integration.android.IntentIntegrator;
/**
* IntentIntegrator for the V4 Android compatibility package.
- *
+ *
* @author Lachezar Dobrev
*/
public final class IntentIntegratorSupportV4 extends IntentIntegrator {
- private final Fragment fragment;
+ private final Fragment mFragment;
/**
- * @param fragment
- * Fragment to handle activity response.
+ * @param fragment Fragment to handle activity response.
*/
public IntentIntegratorSupportV4(Fragment fragment) {
super(fragment.getActivity());
- this.fragment = fragment;
+ this.mFragment = fragment;
}
@Override
protected void startActivityForResult(Intent intent, int code) {
- fragment.startActivityForResult(intent, code);
+ mFragment.startActivityForResult(intent, code);
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java
index caaa07524..40105df4f 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java
@@ -16,13 +16,21 @@
package org.sufficientlysecure.keychain.util;
+import java.util.ArrayList;
import java.util.Iterator;
public class IterableIterator<T> implements Iterable<T> {
private Iterator<T> mIter;
- public IterableIterator(Iterator<T> iter) {
+ public IterableIterator(Iterator<T> iter, boolean failsafe) {
mIter = iter;
+ if(failsafe && mIter == null) {
+ // is there a better way?
+ mIter = new ArrayList<T>().iterator();
+ }
+ }
+ public IterableIterator(Iterator<T> iter) {
+ this(iter, false);
}
public Iterator<T> iterator() {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java
index 7049820e8..7f70867a5 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java
@@ -18,12 +18,12 @@
package org.sufficientlysecure.keychain.util;
-import java.util.List;
-
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
+import java.util.List;
+
public abstract class KeyServer {
- static public class QueryException extends Exception {
+ public static class QueryException extends Exception {
private static final long serialVersionUID = 2703768928624654512L;
public QueryException(String message) {
@@ -31,22 +31,22 @@ public abstract class KeyServer {
}
}
- static public class TooManyResponses extends Exception {
+ public static class TooManyResponses extends Exception {
private static final long serialVersionUID = 2703768928624654513L;
}
- static public class InsufficientQuery extends Exception {
+ public static class InsufficientQuery extends Exception {
private static final long serialVersionUID = 2703768928624654514L;
}
- static public class AddKeyException extends Exception {
+ public static class AddKeyException extends Exception {
private static final long serialVersionUID = -507574859137295530L;
}
abstract List<ImportKeysListEntry> search(String query) throws QueryException, TooManyResponses,
InsufficientQuery;
- abstract String get(long keyId) throws QueryException;
+ abstract String get(String keyIdHex) throws QueryException;
- abstract void add(String armoredText) throws AddKeyException;
+ abstract void add(String armoredKey) throws AddKeyException;
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java
new file mode 100644
index 000000000..14b2a2211
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java
@@ -0,0 +1,18 @@
+/*
+ * 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.util;
+
+public interface KeychainServiceListener {
+ boolean hasServiceStopped();
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java
index bcf275c32..f58f1757a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java
@@ -21,7 +21,6 @@ import org.sufficientlysecure.keychain.Constants;
/**
* Wraps Android Logging to enable or disable debug output using Constants
- *
*/
public final class Log {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java
index 530a81044..2d8fbcd81 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java
@@ -14,48 +14,36 @@ import android.os.Build;
import android.os.Process;
import android.util.Log;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Provider;
-import java.security.SecureRandom;
-import java.security.SecureRandomSpi;
-import java.security.Security;
+import java.io.*;
+import java.security.*;
/**
* Fixes for the output of the default PRNG having low entropy.
- *
+ * <p/>
* The fixes need to be applied via {@link #apply()} before any use of Java Cryptography
* Architecture primitives. A good place to invoke them is in the application's {@code onCreate}.
- *
+ * <p/>
* copied from http://android-developers.blogspot.de/2013/08/some-securerandom-thoughts.html
- *
- *
+ * <p/>
+ * <p/>
* More information on these Android bugs:
* http://blog.k3170makan.com/2013/08/more-details-on-android-jca-prng-flaw.html
* Paper: "Randomly failed! Weaknesses in Java Pseudo Random Number Generators (PRNGs)"
- *
- *
+ * <p/>
+ * <p/>
* Sep 15, 2013:
* On some devices /dev/urandom is non-writable!
* No need to seed /dev/urandom. urandom should have enough seeds from the OS and kernel.
* Only OpenSSL seeds are broken. See http://emboss.github.io/blog/2013/08/21/openssl-prng-is-not-really-fork-safe
- *
+ * <p/>
* see also:
* https://github.com/k9mail/k-9/commit/dda8f64276d4d29c43f86237cd77819c28f22f21
* In addition to a couple of custom ROMs linking /dev/urandom to a non-writable
* random version, now Samsung's SELinux policy also prevents apps from opening
* /dev/urandom for writing. Since we shouldn't need to write to /dev/urandom anyway
* we now simply don't.
- *
- *
+ * <p/>
+ * <p/>
* Sep 17, 2013:
* Updated from official blogpost:
* Update: the original code sample below crashed on a small fraction of Android
@@ -66,10 +54,13 @@ public final class PRNGFixes {
private static final int VERSION_CODE_JELLY_BEAN = 16;
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
- getBuildFingerprintAndDeviceSerial();
+ getBuildFingerprintAndDeviceSerial();
- /** Hidden constructor to prevent instantiation. */
- private PRNGFixes() {}
+ /**
+ * Hidden constructor to prevent instantiation.
+ */
+ private PRNGFixes() {
+ }
/**
* Applies all fixes.
@@ -136,7 +127,7 @@ public final class PRNGFixes {
if ((secureRandomProviders == null)
|| (secureRandomProviders.length < 1)
|| (!LinuxPRNGSecureRandomProvider.class.equals(
- secureRandomProviders[0].getClass()))) {
+ secureRandomProviders[0].getClass()))) {
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
}
@@ -161,7 +152,7 @@ public final class PRNGFixes {
rng2.getProvider().getClass())) {
throw new SecurityException(
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
- + " Provider: " + rng2.getProvider().getClass());
+ + " Provider: " + rng2.getProvider().getClass());
}
}
@@ -175,7 +166,7 @@ public final class PRNGFixes {
super("LinuxPRNG",
1.0,
"A Linux-specific random number provider that uses"
- + " /dev/urandom");
+ + " /dev/urandom");
// Although /dev/urandom is not a SHA-1 PRNG, some apps
// explicitly request a SHA1PRNG SecureRandom and we thus need to
// prevent them from getting the default implementation whose output
@@ -358,4 +349,4 @@ public final class PRNGFixes {
throw new RuntimeException("UTF-8 encoding not supported");
}
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java
index aa21581c6..377a8d5d6 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java
@@ -17,11 +17,7 @@
package org.sufficientlysecure.keychain.util;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.RejectedExecutionHandler;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -32,59 +28,63 @@ import java.util.concurrent.locks.ReentrantLock;
public class PausableThreadPoolExecutor extends ThreadPoolExecutor {
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
- TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
+ TimeUnit unit, BlockingQueue<Runnable> workQueue,
+ RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
- TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
- RejectedExecutionHandler handler) {
+ TimeUnit unit, BlockingQueue<Runnable> workQueue,
+ ThreadFactory threadFactory,
+ RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
- TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
+ TimeUnit unit, BlockingQueue<Runnable> workQueue,
+ ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
- TimeUnit unit, BlockingQueue<Runnable> workQueue) {
+ TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
- private boolean isPaused;
- private ReentrantLock pauseLock = new ReentrantLock();
- private Condition unpaused = pauseLock.newCondition();
+ private boolean mIsPaused;
+ private ReentrantLock mPauseLock = new ReentrantLock();
+ private Condition mUnPaused = mPauseLock.newCondition();
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
- pauseLock.lock();
+ mPauseLock.lock();
try {
- while (isPaused)
- unpaused.await();
+ while (mIsPaused) {
+ mUnPaused.await();
+ }
} catch (InterruptedException ie) {
t.interrupt();
} finally {
- pauseLock.unlock();
+ mPauseLock.unlock();
}
}
public void pause() {
- pauseLock.lock();
+ mPauseLock.lock();
try {
- isPaused = true;
+ mIsPaused = true;
} finally {
- pauseLock.unlock();
+ mPauseLock.unlock();
}
}
public void resume() {
- pauseLock.lock();
+ mPauseLock.lock();
try {
- isPaused = false;
- unpaused.signalAll();
+ mIsPaused = false;
+ mUnPaused.signalAll();
} finally {
- pauseLock.unlock();
+ mPauseLock.unlock();
}
}
-} \ No newline at end of file
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java
index f503227a3..28a12bf37 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java
@@ -25,147 +25,147 @@ public final class Primes {
// taken from http://www.ietf.org/rfc/rfc3526.txt
public static final String P1536 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
public static final String P2048 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
public static final String P3072 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
public static final String P4096 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
- "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
- "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
- "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
- "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
- "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
- "FFFFFFFF FFFFFFFF";
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
+ "FFFFFFFF FFFFFFFF";
public static final String P6144 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
- "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
- "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
- "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
- "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
- "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
- "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
- "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
- "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
- "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
- "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
- "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
- "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
- "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
- "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
- "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
- "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
+ "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
public static final String P8192 =
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
- "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
- "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
- "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
- "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
- "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
- "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
- "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
- "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
- "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
- "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
- "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
- "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
- "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
- "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
- "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
- "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
- "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
- "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
- "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
- "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
- "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
- "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
- "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
- "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
- "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
- "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
- "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
- "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
- "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
- "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
- "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
- "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
- "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
- "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
- "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
- "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
- "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
- "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
- "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
- "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
- "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
- "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
+ "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
+ "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
+ "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
+ "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
+ "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
+ "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
+ "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
+ "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
+ "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
+ "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
+ "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
+ "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
public static BigInteger getBestPrime(int keySize) {
String primeString;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java
index 9e8118e7a..8c3367bea 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java
@@ -18,26 +18,24 @@
package org.sufficientlysecure.keychain.util;
-import java.util.Hashtable;
-
-import org.sufficientlysecure.keychain.Constants;
-
import android.graphics.Bitmap;
import android.graphics.Color;
-
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
+import org.sufficientlysecure.keychain.Constants;
+
+import java.util.Hashtable;
public class QrCodeUtils {
- public final static QRCodeWriter QR_CODE_WRITER = new QRCodeWriter();
+ public static final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter();
/**
* Generate Bitmap with QR Code based on input.
- *
+ *
* @param input
* @param size
* @return QR Code as Bitmap
diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_person.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_person.png
new file mode 100644
index 000000000..9fd81097b
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_person.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_save.png
new file mode 100644
index 000000000..c4b7783cc
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_save.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/icon.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/icon.png
index 571634090..f5487599b 100644
--- a/OpenPGP-Keychain/src/main/res/drawable-hdpi/icon.png
+++ b/OpenPGP-Keychain/src/main/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/revoked_key_small.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/revoked_key_small.png
new file mode 100644
index 000000000..75f45eb54
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-hdpi/revoked_key_small.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-ldpi/icon.png b/OpenPGP-Keychain/src/main/res/drawable-ldpi/icon.png
index 63bdba209..7cd482bff 100644
--- a/OpenPGP-Keychain/src/main/res/drawable-ldpi/icon.png
+++ b/OpenPGP-Keychain/src/main/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_person.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_person.png
new file mode 100644
index 000000000..359da1c12
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_person.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_save.png
new file mode 100644
index 000000000..61304a68c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_save.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/icon.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/icon.png
index bab8c56bb..34f1420ac 100644
--- a/OpenPGP-Keychain/src/main/res/drawable-mdpi/icon.png
+++ b/OpenPGP-Keychain/src/main/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_person.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_person.png
new file mode 100644
index 000000000..03eeb8d6a
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_person.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_save.png
new file mode 100644
index 000000000..29c5f4d3b
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_save.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/icon.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/icon.png
index 79b8e27c6..32584f3ff 100644
--- a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/icon.png
+++ b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/icon.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_person.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_person.png
new file mode 100644
index 000000000..fd1bcdd45
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_person.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_save.png
new file mode 100644
index 000000000..744350049
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_save.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/icon.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/icon.png
index ac8190c93..b2922309f 100644
--- a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/icon.png
+++ b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/icon.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxxhdpi/icon.png b/OpenPGP-Keychain/src/main/res/drawable-xxxhdpi/icon.png
index cdc0fc9f0..93ea6b0f5 100644
--- a/OpenPGP-Keychain/src/main/res/drawable-xxxhdpi/icon.png
+++ b/OpenPGP-Keychain/src/main/res/drawable-xxxhdpi/icon.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable/revoked_key_small.png b/OpenPGP-Keychain/src/main/res/drawable/revoked_key_small.png
new file mode 100644
index 000000000..f9ed0596f
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable/revoked_key_small.png
Binary files differ
diff --git a/OpenPGP-Keychain/src/main/res/drawable/selector_transparent_button.xml b/OpenPGP-Keychain/src/main/res/drawable/selector_transparent_button.xml
new file mode 100644
index 000000000..a2cacf0ad
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/drawable/selector_transparent_button.xml
@@ -0,0 +1,7 @@
+<?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" android:exitFadeDuration="@android:integer/config_shortAnimTime">
+ <item android:state_pressed="true" android:drawable="@color/emphasis" />
+ <item android:drawable="@android:color/transparent" />
+</selector> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout-large/api_apps_list_activity.xml b/OpenPGP-Keychain/src/main/res/layout-large/api_apps_list_activity.xml
new file mode 100644
index 000000000..c0021261e
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout-large/api_apps_list_activity.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
+ <android.support.v4.widget.DrawerLayout
+ android:id="@+id/drawer_layout"
+
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <include layout="@layout/drawer_list"/>
+
+ </android.support.v4.widget.DrawerLayout>
+
+ <include layout="@layout/api_apps_list_content"/>
+
+</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout-large/decrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout-large/decrypt_activity.xml
new file mode 100644
index 000000000..26aed0831
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout-large/decrypt_activity.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <android.support.v4.widget.DrawerLayout
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/drawer_list"/>
+
+ </android.support.v4.widget.DrawerLayout>
+
+ <include layout="@layout/decrypt_content"/>
+
+</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout-large/encrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout-large/encrypt_activity.xml
new file mode 100644
index 000000000..7d0d44074
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout-large/encrypt_activity.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <android.support.v4.widget.DrawerLayout
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ xmlns:fontawesometext="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/drawer_list"/>
+
+ </android.support.v4.widget.DrawerLayout>
+
+ <include layout="@layout/encrypt_content"/>
+</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout-large/import_keys_activity.xml b/OpenPGP-Keychain/src/main/res/layout-large/import_keys_activity.xml
new file mode 100644
index 000000000..2cb408441
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout-large/import_keys_activity.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v4.widget.DrawerLayout
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <include layout="@layout/drawer_list"/>
+
+ </android.support.v4.widget.DrawerLayout>
+
+ <include layout="@layout/import_keys_content"/>
+
+</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout-large/key_list_activity.xml b/OpenPGP-Keychain/src/main/res/layout-large/key_list_activity.xml
new file mode 100644
index 000000000..6636f12ff
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout-large/key_list_activity.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <android.support.v4.widget.DrawerLayout
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/drawer_list"/>
+
+ </android.support.v4.widget.DrawerLayout>
+
+ <include layout="@layout/key_list_content"/>
+
+</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_account_settings_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_account_settings_activity.xml
new file mode 100644
index 000000000..3557c1f00
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/api_account_settings_activity.xml
@@ -0,0 +1,20 @@
+<?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:padding="16dp"
+ android:orientation="vertical">
+
+ <fragment
+ android:id="@+id/api_account_settings_fragment"
+ android:name="org.sufficientlysecure.keychain.remote.ui.AccountSettingsFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_account_settings_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/api_account_settings_fragment.xml
new file mode 100644
index 000000000..32843eb29
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/api_account_settings_fragment.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/api_account_settings_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginRight="6dp"
+ android:src="@drawable/ic_action_person" />
+
+ <TextView
+ android:id="@+id/api_account_settings_acc_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@+id/api_account_settings_icon"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:text="Name (set in-code)"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ </RelativeLayout>
+
+ <fragment
+ android:id="@+id/api_account_settings_select_key_fragment"
+ android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:layout="@layout/select_secret_key_layout_fragment" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/api_account_settings_create_key"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="4dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="4dp"
+ android:text="@string/api_settings_create_key"
+ bootstrapbutton:bb_icon_left="fa-key"
+ bootstrapbutton:bb_size="default"
+ bootstrapbutton:bb_type="default" />
+
+ <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ custom:foldedLabel="@string/api_settings_show_advanced"
+ custom:unFoldedLabel="@string/api_settings_hide_advanced"
+ custom:foldedIcon="fa-chevron-right"
+ custom:unFoldedIcon="fa-chevron-down">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/label_encryption_algorithm"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Spinner
+ android:id="@+id/api_account_settings_encryption_algorithm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/label_hash_algorithm"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Spinner
+ android:id="@+id/api_account_settings_hash_algorithm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/label_message_compression"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Spinner
+ android:id="@+id/api_account_settings_compression"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_accounts_adapter_list_item.xml b/OpenPGP-Keychain/src/main/res/layout/api_accounts_adapter_list_item.xml
new file mode 100644
index 000000000..d31ae52d7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/api_accounts_adapter_list_item.xml
@@ -0,0 +1,27 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="8dp"
+ android:paddingRight="4dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:id="@+id/imageView"
+ android:src="@drawable/ic_action_person" />
+
+ <TextView
+ android:id="@+id/api_accounts_adapter_item_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:text="Account Name"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml
index d83c8e87d..1377acf0e 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_activity.xml
@@ -6,16 +6,28 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:padding="16dp"
android:orientation="vertical">
<fragment
android:id="@+id/api_app_settings_fragment"
- android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsFragment"
+ android:name="org.sufficientlysecure.keychain.remote.ui.AppSettingsFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="@layout/api_app_settings_fragment" />
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/api_settings_accounts"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <FrameLayout
+ android:id="@+id/api_accounts_list_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" />
+
</LinearLayout>
</ScrollView>
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml
index a8b68859b..96271d418 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_app_settings_fragment.xml
@@ -2,6 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -35,64 +36,13 @@
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
- <fragment
- android:id="@+id/api_app_settings_select_key_fragment"
- android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment"
+ <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- tools:layout="@layout/select_secret_key_layout_fragment" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/api_app_settings_advanced_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- android:text="@string/api_settings_show_advanced"
- bootstrapbutton:bb_icon_left="fa-caret-up"
- bootstrapbutton:bb_size="default"
- bootstrapbutton:bb_type="default" />
-
- <LinearLayout
- android:id="@+id/api_app_settings_advanced"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/label_encryption_algorithm"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <Spinner
- android:id="@+id/api_app_settings_encryption_algorithm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/label_hash_algorithm"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <Spinner
- android:id="@+id/api_app_settings_hash_algorithm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/label_message_compression"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <Spinner
- android:id="@+id/api_app_settings_compression"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="match_parent"
+ custom:foldedLabel="@string/api_settings_show_info"
+ custom:unFoldedLabel="@string/api_settings_hide_info"
+ custom:foldedIcon="fa-chevron-right"
+ custom:unFoldedIcon="fa-chevron-down">
<TextView
android:layout_width="match_parent"
@@ -119,5 +69,7 @@
android:layout_height="wrap_content"
android:text="Base64 encoded signature"
android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout>
+
</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_apps_list_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_apps_list_activity.xml
index 71fbcfb12..9f95e9f3b 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_apps_list_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_apps_list_activity.xml
@@ -4,16 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <fragment
- android:id="@+id/crypto_consumers_list_fragment"
- android:name="org.sufficientlysecure.keychain.service.remote.RegisteredAppsListFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </FrameLayout>
+ <include layout="@layout/api_apps_list_content"/>
<include layout="@layout/drawer_list" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_apps_list_content.xml b/OpenPGP-Keychain/src/main/res/layout/api_apps_list_content.xml
new file mode 100644
index 000000000..9f9b99045
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/api_apps_list_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content_frame"
+ android:layout_marginLeft="@dimen/drawer_content_padding"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <fragment
+ android:id="@+id/crypto_consumers_list_fragment"
+ android:name="org.sufficientlysecure.keychain.remote.ui.AppsListFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_remote_create_account.xml b/OpenPGP-Keychain/src/main/res/layout/api_remote_create_account.xml
new file mode 100644
index 000000000..3aee9094f
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/api_remote_create_account.xml
@@ -0,0 +1,29 @@
+<?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="wrap_content">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/api_remote_create_account_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="3dip"
+ android:text="@string/api_create_account_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <fragment
+ android:id="@+id/api_account_settings_fragment"
+ android:name="org.sufficientlysecure.keychain.remote.ui.AccountSettingsFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:layout="@layout/api_app_settings_fragment" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_error_message.xml b/OpenPGP-Keychain/src/main/res/layout/api_remote_error_message.xml
index 5927dbf43..48aa89d4f 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_error_message.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_remote_error_message.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_remote_register_app.xml
index aa9d59004..f85f3b8f7 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_remote_register_app.xml
@@ -20,7 +20,7 @@
<fragment
android:id="@+id/api_app_settings_fragment"
- android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsFragment"
+ android:name="org.sufficientlysecure.keychain.remote.ui.AppSettingsFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="@layout/api_app_settings_fragment" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_select_pub_keys_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_remote_select_pub_keys.xml
index 877b4e74e..a10592607 100644
--- a/OpenPGP-Keychain/src/main/res/layout/api_app_select_pub_keys_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/api_remote_select_pub_keys.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
diff --git a/OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml b/OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml
index ddb424ee8..6cd140739 100644
--- a/OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/certify_key_activity.xml
@@ -35,6 +35,93 @@
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="14dp"
+ android:text="KEY TO SIGN" />
+
+ <TableLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:shrinkColumns="1">
+
+ <TableRow
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_key_id" />
+
+ <TextView
+ android:id="@+id/key_id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:text=""
+ android:typeface="monospace" />
+ </TableRow>
+
+ <TableRow
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_main_user_id" />
+
+ <TextView
+ android:id="@+id/main_user_id"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:typeface="monospace" />
+
+ </TableRow>
+
+ <TableRow
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_fingerprint" />
+
+ <TextView
+ android:id="@+id/fingerprint"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:typeface="monospace" />
+
+ </TableRow>
+
+ </TableLayout>
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_uids_to_sign" />
+
+ <org.sufficientlysecure.keychain.ui.widget.FixedListView
+ android:id="@+id/user_ids"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="14dp"
android:text="@string/section_upload_key" />
<CheckBox
diff --git a/OpenPGP-Keychain/src/main/res/layout/create_key_dialog.xml b/OpenPGP-Keychain/src/main/res/layout/create_key_dialog.xml
index a2e908433..57a1b865f 100644
--- a/OpenPGP-Keychain/src/main/res/layout/create_key_dialog.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/create_key_dialog.xml
@@ -17,6 +17,13 @@
android:padding="4dp"
android:text="@string/key_creation_el_gamal_info" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:padding="4dp"
+ android:text="@string/key_creation_weak_rsa_info" />
+
<TableRow>
<TextView
diff --git a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml
index e6c81c3fc..c4709a67e 100644
--- a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml
@@ -5,208 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true"
- android:orientation="vertical">
-
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingTop="4dp"
- android:paddingLeft="10dp"
- android:paddingRight="10dp">
-
- <RelativeLayout
- android:id="@+id/signature"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clickable="true"
- android:orientation="horizontal"
- android:padding="4dp"
- android:paddingLeft="10dp"
- android:paddingRight="10dp">
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/relativeLayout">
-
- <ImageView
- android:id="@+id/ic_signature"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/signed_large" />
-
- <ImageView
- android:id="@+id/ic_signature_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/overlay_error" />
- </RelativeLayout>
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/lookup_key"
- android:visibility="gone"
- android:layout_width="wrap_content"
- android:layout_height="50dp"
- android:padding="4dp"
- android:text="@string/btn_lookup_key"
- bootstrapbutton:bb_icon_left="fa-download"
- bootstrapbutton:bb_type="info"
- bootstrapbutton:bb_size="small"
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true" />
-
- <TextView
- android:id="@+id/mainUserId"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:text="Main User Id"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_alignTop="@+id/linearLayout"
- android:layout_toRightOf="@+id/relativeLayout" />
-
- <TextView
- android:id="@+id/mainUserIdRest"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:text="Main User Id Rest"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_below="@+id/mainUserId"
- android:layout_toRightOf="@+id/relativeLayout" />
- </RelativeLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/sourcePrevious"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_previous" />
-
- <TextView
- android:id="@+id/sourceLabel"
- style="@style/SectionHeader"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_horizontal|center_vertical"
- android:text="@string/label_message"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <ImageView
- android:id="@+id/sourceNext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_next" />
- </LinearLayout>
-
- <ViewFlipper
- android:id="@+id/source"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1">
-
- <LinearLayout
- android:id="@+id/sourceMessage"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="4dp">
-
- <EditText
- android:id="@+id/message"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="top"
- android:inputType="text|textCapSentences|textMultiLine|textLongMessage"
- android:scrollHorizontally="true" />
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/sourceFile"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="4dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <EditText
- android:id="@+id/filename"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:inputType="textNoSuggestions" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/btn_browse"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="4dp"
- bootstrapbutton:bb_icon_left="fa-folder-open"
- bootstrapbutton:bb_roundedCorners="true"
- bootstrapbutton:bb_size="default"
- bootstrapbutton:bb_type="default" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <CheckBox
- android:id="@+id/deleteAfterDecryption"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/label_delete_after_decryption" />
- </LinearLayout>
- </LinearLayout>
- </ViewFlipper>
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:text="@string/section_decrypt_verify" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="4dp">
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/action_decrypt"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:padding="4dp"
- android:text="@string/btn_decrypt_verify"
- bootstrapbutton:bb_icon_left="fa-unlock"
- bootstrapbutton:bb_type="info" />
- </LinearLayout>
- </LinearLayout>
- </ScrollView>
- </LinearLayout>
+ <include layout="@layout/decrypt_content"/>
<include layout="@layout/drawer_list" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/decrypt_content.xml b/OpenPGP-Keychain/src/main/res/layout/decrypt_content.xml
new file mode 100644
index 000000000..a847d9e46
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/decrypt_content.xml
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/content_frame"
+ android:layout_marginLeft="@dimen/drawer_content_padding"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingTop="4dp"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp">
+
+ <RelativeLayout
+ android:id="@+id/signature"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:orientation="horizontal"
+ android:padding="4dp"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/relativeLayout">
+
+ <ImageView
+ android:id="@+id/ic_signature"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/signed_large"/>
+
+ <ImageView
+ android:id="@+id/ic_signature_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/overlay_error"/>
+ </RelativeLayout>
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/lookup_key"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="50dp"
+ android:padding="4dp"
+ android:text="@string/btn_lookup_key"
+ bootstrapbutton:bb_icon_left="fa-download"
+ bootstrapbutton:bb_type="info"
+ bootstrapbutton:bb_size="small"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"/>
+
+ <TextView
+ android:id="@+id/mainUserId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:text="@string/label_main_user_id"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_toRightOf="@+id/relativeLayout"/>
+
+ <TextView
+ android:id="@+id/mainUserIdRest"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:text="Main User Id Rest"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_below="@+id/mainUserId"
+ android:layout_toRightOf="@+id/relativeLayout"/>
+ </RelativeLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/sourcePrevious"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_previous"/>
+
+ <TextView
+ android:id="@+id/sourceLabel"
+ style="@style/SectionHeader"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_horizontal|center_vertical"
+ android:text="@string/label_message"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <ImageView
+ android:id="@+id/sourceNext"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_next"/>
+ </LinearLayout>
+
+ <ViewFlipper
+ android:id="@+id/source"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:id="@+id/sourceMessage"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="4dp">
+
+ <EditText
+ android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="top"
+ android:inputType="text|textCapSentences|textMultiLine|textLongMessage"
+ android:scrollHorizontally="true"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/sourceFile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <EditText
+ android:id="@+id/filename"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="top|left"
+ android:inputType="textMultiLine|textUri"
+ android:lines="4"
+ android:maxLines="10"
+ android:minLines="2"
+ android:scrollbars="vertical"/>
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/btn_browse"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ bootstrapbutton:bb_icon_left="fa-folder-open"
+ bootstrapbutton:bb_roundedCorners="true"
+ bootstrapbutton:bb_size="default"
+ bootstrapbutton:bb_type="default"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <CheckBox
+ android:id="@+id/deleteAfterDecryption"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_delete_after_decryption"/>
+ </LinearLayout>
+ </LinearLayout>
+ </ViewFlipper>
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:text="@string/section_decrypt_verify"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="4dp">
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_decrypt"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:text="@string/btn_decrypt_verify"
+ bootstrapbutton:bb_icon_left="fa-unlock"
+ bootstrapbutton:bb_type="info"/>
+ </LinearLayout>
+ </LinearLayout>
+</ScrollView> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml b/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml
index 18210afc5..ab00c0073 100644
--- a/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml
@@ -9,10 +9,10 @@
-->
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/left_drawer"
- android:layout_width="240dp"
+ android:layout_width="@dimen/drawer_size"
android:layout_height="match_parent"
android:layout_gravity="start"
- android:background="#fff"
+ android:background="@color/white"
android:choiceMode="singleChoice"
android:divider="@color/bg_gray"
android:dividerHeight="1dp" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/edit_key_key_item.xml b/OpenPGP-Keychain/src/main/res/layout/edit_key_key_item.xml
index 499fd5aa9..090115d62 100644
--- a/OpenPGP-Keychain/src/main/res/layout/edit_key_key_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/edit_key_key_item.xml
@@ -51,7 +51,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="5dip"
- android:text="Name" />
+ android:text="@string/label_name" />
</TableRow>
<TableRow>
diff --git a/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml b/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml
index 663949d8e..a8d1dc674 100644
--- a/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml
@@ -49,7 +49,7 @@
android:paddingRight="5dip"
android:text="@string/label_email" />
- <EditText
+ <AutoCompleteTextView
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -71,7 +71,8 @@
android:id="@+id/comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1" />
+ android:layout_weight="1"
+ android:inputType="text"/>
</TableRow>
</TableLayout>
diff --git a/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml
index 27e29eddb..6484c9b7b 100644
--- a/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/encrypt_activity.xml
@@ -1,350 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ xmlns:fontawesometext="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport="true">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="10dp"
- android:paddingRight="10dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="4dp">
-
- <ImageView
- android:id="@+id/modePrevious"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_previous" />
-
- <TextView
- android:id="@+id/modeLabel"
- style="@style/SectionHeader"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_horizontal|center_vertical"
- android:text="@string/label_asymmetric" />
-
- <ImageView
- android:id="@+id/modeNext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_next" />
- </LinearLayout>
-
- <ViewFlipper
- android:id="@+id/mode"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <LinearLayout
- android:id="@+id/modeAsymmetric"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="4dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <CheckBox
- android:id="@+id/sign"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/label_sign" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="16dp">
-
- <TextView
- android:id="@+id/mainUserId"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:ellipsize="end"
- android:singleLine="true"
- android:text="Sign User Id"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:id="@+id/mainUserIdRest"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:ellipsize="end"
- android:singleLine="true"
- android:text="Sign email"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingBottom="3dip">
-
- <TextView
- android:id="@+id/label_selectPublicKeys"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:text="@string/label_select_public_keys"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/btn_selectEncryptKeys"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_margin="4dp"
- android:text="@string/btn_select_encrypt_keys"
- bootstrapbutton:bb_icon_left="fa-user"
- bootstrapbutton:bb_size="default"
- bootstrapbutton:bb_type="default" />
- </LinearLayout>
- </LinearLayout>
-
- <TableLayout
- android:id="@+id/modeSymmetric"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="4dp"
- android:stretchColumns="1">
-
- <TableRow>
-
- <TextView
- android:id="@+id/label_passphrase"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingRight="10dip"
- android:text="@string/label_passphrase"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <EditText
- android:id="@+id/passphrase"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="textPassword" />
- </TableRow>
-
- <TableRow>
-
- <TextView
- android:id="@+id/label_passphraseAgain"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingRight="10dip"
- android:text="@string/label_passphrase_again"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <EditText
- android:id="@+id/passphraseAgain"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="textPassword" />
- </TableRow>
- </TableLayout>
- </ViewFlipper>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="4dp">
-
- <ImageView
- android:id="@+id/sourcePrevious"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_previous" />
-
- <TextView
- android:id="@+id/sourceLabel"
- style="@style/SectionHeader"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_horizontal|center_vertical"
- android:text="@string/label_message"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <ImageView
- android:id="@+id/sourceNext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_next" />
- </LinearLayout>
-
- <ViewFlipper
- android:id="@+id/source"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1">
-
- <LinearLayout
- android:id="@+id/sourceMessage"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="4dp">
-
- <EditText
- android:id="@+id/message"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="top"
- android:inputType="text|textCapSentences|textMultiLine|textLongMessage" />
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/sourceFile"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="4dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <EditText
- android:id="@+id/filename"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:inputType="textNoSuggestions" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/btn_browse"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="4dp"
- bootstrapbutton:bb_icon_left="fa-folder-open"
- bootstrapbutton:bb_roundedCorners="true"
- bootstrapbutton:bb_size="default"
- bootstrapbutton:bb_type="default" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <TextView
- android:id="@+id/label_fileCompression"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:paddingRight="10dip"
- android:text="@string/label_file_compression"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <Spinner
- android:id="@+id/fileCompression"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <CheckBox
- android:id="@+id/deleteAfterEncryption"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/label_delete_after_encryption" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <CheckBox
- android:id="@+id/asciiArmour"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/label_ascii_armor" />
- </LinearLayout>
- </LinearLayout>
- </ViewFlipper>
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:text="@string/section_encrypt_and_or_sign" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="4dp">
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/action_encrypt_share"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:padding="4dp"
- android:layout_weight="1"
- android:text="@string/btn_share"
- bootstrapbutton:bb_icon_left="fa-lock"
- bootstrapbutton:bb_type="info" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/action_encrypt_clipboard"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:padding="4dp"
- android:layout_weight="1"
- android:text="@string/btn_clipboard"
- bootstrapbutton:bb_icon_left="fa-lock"
- bootstrapbutton:bb_type="info" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/action_encrypt_file"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:padding="4dp"
- android:visibility="gone"
- android:text="@string/btn_encrypt_file"
- bootstrapbutton:bb_icon_left="fa-lock"
- bootstrapbutton:bb_type="info" />
- </LinearLayout>
- </LinearLayout>
- </ScrollView>
+ <include layout="@layout/encrypt_content"/>
<include layout="@layout/drawer_list" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/encrypt_content.xml b/OpenPGP-Keychain/src/main/res/layout/encrypt_content.xml
new file mode 100644
index 000000000..1dba66cfa
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/encrypt_content.xml
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/content_frame"
+ android:layout_marginLeft="@dimen/drawer_content_padding"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="4dp">
+
+ <ImageView
+ android:id="@+id/modePrevious"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_previous"/>
+
+ <TextView
+ android:id="@+id/modeLabel"
+ style="@style/SectionHeader"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_horizontal|center_vertical"
+ android:text="@string/label_asymmetric"/>
+
+ <ImageView
+ android:id="@+id/modeNext"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_next"/>
+ </LinearLayout>
+
+ <ViewFlipper
+ android:id="@+id/mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:id="@+id/modeAsymmetric"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <CheckBox
+ android:id="@+id/sign"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_sign"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="4dip">
+
+ <TextView
+ android:id="@+id/mainUserId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:text="@string/label_sign_user_id"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <TextView
+ android:id="@+id/mainUserIdRest"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:text="@string/label_sign_email"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingBottom="3dip">
+
+ <TextView
+ android:id="@+id/label_selectPublicKeys"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:text="@string/label_select_public_keys"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/btn_selectEncryptKeys"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_margin="4dp"
+ android:text="@string/btn_select_encrypt_keys"
+ bootstrapbutton:bb_icon_left="fa-user"
+ bootstrapbutton:bb_size="default"
+ bootstrapbutton:bb_type="default"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <TableLayout
+ android:id="@+id/modeSymmetric"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="4dp"
+ android:stretchColumns="1">
+
+ <TableRow>
+
+ <TextView
+ android:id="@+id/label_passphrase"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_passphrase"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <EditText
+ android:id="@+id/passphrase"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"/>
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:id="@+id/label_passphraseAgain"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_passphrase_again"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <EditText
+ android:id="@+id/passphraseAgain"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"/>
+ </TableRow>
+ </TableLayout>
+ </ViewFlipper>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="4dp">
+
+ <ImageView
+ android:id="@+id/sourcePrevious"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_previous"/>
+
+ <TextView
+ android:id="@+id/sourceLabel"
+ style="@style/SectionHeader"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_horizontal|center_vertical"
+ android:text="@string/label_message"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <ImageView
+ android:id="@+id/sourceNext"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_next"/>
+ </LinearLayout>
+
+ <ViewFlipper
+ android:id="@+id/source"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:id="@+id/sourceMessage"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="4dp">
+
+ <EditText
+ android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="top"
+ android:inputType="text|textCapSentences|textMultiLine|textLongMessage"
+ android:hint="@string/encrypt_content_edit_text_hint"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/sourceFile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="4dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <EditText
+ android:id="@+id/filename"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="top|left"
+ android:inputType="textMultiLine|textUri"
+ android:lines="4"
+ android:maxLines="10"
+ android:minLines="2"
+ android:scrollbars="vertical"/>
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/btn_browse"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ bootstrapbutton:bb_icon_left="fa-folder-open"
+ bootstrapbutton:bb_roundedCorners="true"
+ bootstrapbutton:bb_size="default"
+ bootstrapbutton:bb_type="default"/>
+ </LinearLayout>
+
+ <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ custom:foldedLabel="@string/btn_encryption_advanced_settings_show"
+ custom:unFoldedLabel="@string/btn_encryption_advanced_settings_hide"
+ custom:foldedIcon="fa-chevron-right"
+ custom:unFoldedIcon="fa-chevron-down">
+
+ <include layout="@layout/encrypt_content_adv_settings"/>
+
+ </org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout>
+
+ </LinearLayout>
+ </ViewFlipper>
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:text="@string/section_encrypt_and_or_sign"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="4dp">
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_encrypt_share"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:layout_weight="1"
+ android:text="@string/btn_share"
+ bootstrapbutton:bb_icon_left="fa-share-square"
+ bootstrapbutton:bb_type="info"/>
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_encrypt_clipboard"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:layout_weight="1"
+ android:text="@string/btn_clipboard"
+ bootstrapbutton:bb_icon_left="fa-clipboard"
+ bootstrapbutton:bb_type="info"/>
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_encrypt_file"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:visibility="gone"
+ android:text="@string/btn_encrypt_file"
+ bootstrapbutton:bb_icon_left="fa-lock"
+ bootstrapbutton:bb_type="info"/>
+ </LinearLayout>
+ </LinearLayout>
+</ScrollView>
diff --git a/OpenPGP-Keychain/src/main/res/layout/encrypt_content_adv_settings.xml b/OpenPGP-Keychain/src/main/res/layout/encrypt_content_adv_settings.xml
new file mode 100644
index 000000000..2281759d1
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/encrypt_content_adv_settings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/label_fileCompression"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:paddingRight="10dip"
+ android:text="@string/label_file_compression"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+
+ <Spinner
+ android:id="@+id/fileCompression"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <CheckBox
+ android:id="@+id/deleteAfterEncryption"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_delete_after_encryption"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <CheckBox
+ android:id="@+id/shareAfterEncryption"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_share_after_encryption"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <CheckBox
+ android:id="@+id/asciiArmour"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_ascii_armor"/>
+ </LinearLayout>
+</merge> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/file_dialog.xml b/OpenPGP-Keychain/src/main/res/layout/file_dialog.xml
index a2939f571..83d697001 100644
--- a/OpenPGP-Keychain/src/main/res/layout/file_dialog.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/file_dialog.xml
@@ -26,8 +26,8 @@
android:layout_weight="1"
android:gravity="top|left"
android:inputType="textMultiLine|textUri"
- android:lines="2"
- android:maxLines="6"
+ android:lines="4"
+ android:maxLines="10"
android:minLines="2"
android:scrollbars="vertical" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/foldable_linearlayout.xml b/OpenPGP-Keychain/src/main/res/layout/foldable_linearlayout.xml
new file mode 100644
index 000000000..2b863d52b
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/foldable_linearlayout.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:fontawesometext="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:id="@+id/foldableControl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:clickable="true">
+
+ <com.beardedhen.androidbootstrap.FontAwesomeText
+ android:id="@+id/foldableIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="10dp"
+ android:textSize="12sp"
+ android:paddingTop="@dimen/padding_medium"
+ android:paddingBottom="@dimen/padding_medium"
+ fontawesometext:fa_icon="fa-chevron-right"/>
+
+ <TextView
+ android:id="@+id/foldableText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/none"
+ android:paddingTop="@dimen/padding_medium"
+ android:paddingBottom="@dimen/padding_medium"
+ android:textColor="@color/emphasis"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/foldableContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:visibility="gone"/>
+</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/import_keys_activity.xml b/OpenPGP-Keychain/src/main/res/layout/import_keys_activity.xml
index d7794ace3..b11f99757 100644
--- a/OpenPGP-Keychain/src/main/res/layout/import_keys_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/import_keys_activity.xml
@@ -5,58 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true" >
-
- <FrameLayout
- android:id="@+id/import_navigation_fragment"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:orientation="vertical"
- android:paddingLeft="4dp"
- android:paddingRight="4dp" />
-
- <LinearLayout
- android:id="@+id/import_footer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:orientation="vertical"
- android:paddingLeft="10dp"
- android:paddingRight="10dp" >
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/import_import"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:padding="4dp"
- android:text="@string/import_import"
- bootstrapbutton:bb_icon_left="fa-download"
- bootstrapbutton:bb_type="info" />
-
- <!-- <com.beardedhen.androidbootstrap.BootstrapButton -->
- <!-- android:id="@+id/import_sign_and_upload" -->
- <!-- android:layout_width="match_parent" -->
- <!-- android:layout_height="60dp" -->
- <!-- android:padding="4dp" -->
- <!-- android:text="@string/import_sign_and_upload" -->
- <!-- bootstrapbutton:bb_type="info" /> -->
- </LinearLayout>
-
- <FrameLayout
- android:id="@+id/import_keys_list_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_above="@+id/import_footer"
- android:layout_alignParentLeft="true"
- android:layout_below="@+id/import_navigation_fragment"
- android:orientation="vertical"
- android:paddingLeft="4dp"
- android:paddingRight="4dp" />
- </RelativeLayout>
+ <include layout="@layout/import_keys_content"/>
<include layout="@layout/drawer_list" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/import_keys_content.xml b/OpenPGP-Keychain/src/main/res/layout/import_keys_content.xml
new file mode 100644
index 000000000..fae8147e5
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/import_keys_content.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto" android:id="@+id/content_frame"
+ android:layout_marginLeft="@dimen/drawer_content_padding"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true">
+
+ <FrameLayout
+ android:id="@+id/import_navigation_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:orientation="vertical"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp"/>
+
+ <LinearLayout
+ android:id="@+id/import_footer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:orientation="vertical"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp">
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/import_import"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:text="@string/import_import"
+ bootstrapbutton:bb_icon_left="fa-download"
+ bootstrapbutton:bb_type="info"/>
+
+ <!-- <com.beardedhen.androidbootstrap.BootstrapButton -->
+ <!-- android:id="@+id/import_sign_and_upload" -->
+ <!-- android:layout_width="match_parent" -->
+ <!-- android:layout_height="60dp" -->
+ <!-- android:padding="4dp" -->
+ <!-- android:text="@string/import_sign_and_upload" -->
+ <!-- bootstrapbutton:bb_type="info" /> -->
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/import_keys_list_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_above="@+id/import_footer"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@+id/import_navigation_fragment"
+ android:orientation="vertical"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp"/>
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml b/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml
index 37d1c5702..f5a39f115 100644
--- a/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="3dip"
@@ -23,7 +23,7 @@
android:singleLine="true" >
<LinearLayout
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
@@ -48,17 +48,10 @@
android:id="@+id/mainUserId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Main User ID"
+ android:text="@string/label_main_user_id"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
- android:id="@+id/fingerprint"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="fingerprint"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <TextView
android:id="@+id/mainUserIdRest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -77,10 +70,11 @@
<TextView
android:id="@+id/keyId"
android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:text="BBBBBBBB"
+ android:layout_height="wrap_content"
+ android:text="0xBBBBBBBBBBBBBBBB"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:typeface="monospace" />
+ android:typeface="monospace"
+ android:layout_weight="1" />
<TextView
android:id="@+id/algorithm"
@@ -89,6 +83,14 @@
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
+ android:id="@+id/fingerprint"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="fingerprint"
+ android:typeface="monospace"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -99,10 +101,10 @@
<LinearLayout
android:id="@+id/list"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="36dip"
android:orientation="vertical" >
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_activity.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_activity.xml
new file mode 100644
index 000000000..fcb376fa8
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_activity.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <include layout="@layout/key_list_content"/>
+
+ <include layout="@layout/drawer_list" />
+
+</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_content.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_content.xml
new file mode 100644
index 000000000..e58e42961
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content_frame"
+ android:layout_marginLeft="@dimen/drawer_content_padding"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <fragment
+ android:id="@+id/key_list_fragment"
+ android:name="org.sufficientlysecure.keychain.ui.KeyListFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_fragment.xml
new file mode 100644
index 000000000..f2430f213
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_fragment.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <!--rebuild functionality of ListFragment -->
+ <LinearLayout
+ android:id="@+id/key_list_progress_container"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="visible"
+ android:gravity="center">
+
+ <ProgressBar
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text=""
+ android:paddingTop="4dip"
+ android:singleLine="true" />
+
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/key_list_list_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <se.emilsjolander.stickylistheaders.StickyListHeadersListView
+ android:id="@+id/key_list_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:drawSelectorOnTop="true"
+ android:fastScrollEnabled="true"
+ android:paddingBottom="16dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="32dp"
+ android:scrollbarStyle="outsideOverlay" />
+
+ <LinearLayout
+ android:id="@+id/key_list_empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="@string/key_list_empty_text1"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:gravity="center"
+ android:text="@string/key_list_empty_text2"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/key_list_empty_button_create"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:text="@string/key_list_empty_button_create"
+ bootstrapbutton:bb_icon_left="fa-plus"
+ bootstrapbutton:bb_type="default" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:gravity="center"
+ android:text="@string/key_list_empty_text3"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/key_list_empty_button_import"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:text="@string/key_list_empty_button_import"
+ bootstrapbutton:bb_icon_left="fa-download"
+ bootstrapbutton:bb_type="default" />
+ </LinearLayout>
+
+ </FrameLayout>
+
+
+</FrameLayout>
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_header.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_header.xml
new file mode 100644
index 000000000..09ac1c856
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_header.xml
@@ -0,0 +1,30 @@
+<?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="wrap_content" >
+
+ <org.sufficientlysecure.keychain.ui.widget.UnderlineTextView
+ android:id="@+id/stickylist_header_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|left"
+ android:padding="8dp"
+ android:textColor="@color/emphasis"
+ android:textSize="17sp"
+ android:textStyle="bold"
+ android:text="header text" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="contact count"
+ android:id="@+id/contacts_num"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
+ android:layout_marginRight="10px"
+ android:visibility="visible"
+ android:textColor="@android:color/darker_gray" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml
new file mode 100644
index 000000000..0abae8bbb
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml
@@ -0,0 +1,78 @@
+<?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:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:orientation="horizontal"
+ android:descendantFocusability="blocksDescendants"
+ android:focusable="false">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:focusable="true"
+ android:orientation="vertical"
+ android:paddingLeft="8dp"
+ android:paddingRight="4dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+
+ <TextView
+ android:id="@+id/mainUserId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/label_main_user_id"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/mainUserIdRest"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:text="user@example.com"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </LinearLayout>
+
+ <View
+ android:id="@+id/status_divider"
+ android:layout_width="1dip"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="8dp"
+ android:background="?android:attr/listDivider" />
+
+ <FrameLayout
+ android:id="@+id/status_layout"
+ android:layout_width="80dp"
+ android:layout_height="match_parent">
+
+ <Button
+ android:background="@drawable/selector_transparent_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/edit"
+ android:focusable="false"
+ android:enabled="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/black"
+ android:text="@string/edit" />
+
+ <TextView
+ android:id="@+id/revoked"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="8dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/revoked"
+ android:textColor="#e00"
+ android:layout_gravity="center" />
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_public_activity.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_public_activity.xml
deleted file mode 100644
index f0e843e56..000000000
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_public_activity.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/drawer_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <fragment
- android:id="@+id/key_list_public_fragment"
- android:name="org.sufficientlysecure.keychain.ui.KeyListPublicFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </FrameLayout>
-
- <include layout="@layout/drawer_list" />
-
-</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_public_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_public_fragment.xml
deleted file mode 100644
index f3a21e1bf..000000000
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_public_fragment.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <se.emilsjolander.stickylistheaders.StickyListHeadersListView
- android:id="@+id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipToPadding="false"
- android:drawSelectorOnTop="true"
- android:fastScrollEnabled="true"
- android:paddingBottom="16dp"
- android:paddingLeft="16dp"
- android:paddingRight="32dp"
- android:scrollbarStyle="outsideOverlay" />
-
- <LinearLayout
- android:id="@+id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical"
- android:visibility="gone" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@string/key_list_empty_text1"
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="4dp"
- android:gravity="center"
- android:text="@string/key_list_empty_text2"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/key_list_empty_button_create"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="4dp"
- android:text="@string/key_list_empty_button_create"
- bootstrapbutton:bb_icon_left="fa-plus"
- bootstrapbutton:bb_type="default" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="4dp"
- android:gravity="center"
- android:text="@string/key_list_empty_text3"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <com.beardedhen.androidbootstrap.BootstrapButton
- android:id="@+id/key_list_empty_button_import"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="4dp"
- android:text="@string/key_list_empty_button_import"
- bootstrapbutton:bb_icon_left="fa-download"
- bootstrapbutton:bb_type="default" />
- </LinearLayout>
-
-</FrameLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_public_header.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_public_header.xml
deleted file mode 100644
index 5768e4153..000000000
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_public_header.xml
+++ /dev/null
@@ -1,16 +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="wrap_content" >
-
- <org.sufficientlysecure.keychain.ui.widget.UnderlineTextView
- android:id="@+id/stickylist_header_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="start|left"
- android:padding="8dp"
- android:textColor="@color/emphasis"
- android:textSize="17sp"
- android:textStyle="bold" />
-
-</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml
deleted file mode 100644
index 9307ab2e5..000000000
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_public_item.xml
+++ /dev/null
@@ -1,45 +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="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:layout_marginRight="?android:attr/scrollbarSize"
- android:gravity="center_vertical"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:singleLine="true">
-
- <TextView
- android:id="@+id/mainUserId"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Main User ID"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true" />
-
- <TextView
- android:id="@+id/mainUserIdRest"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&lt;user@example.com>"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_below="@+id/mainUserId"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true" />
-
- <TextView
- android:id="@+id/revoked"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:text="@string/revoked"
- android:textColor="#e00"
- android:visibility="gone"
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true" />
-
-</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml
deleted file mode 100644
index cd208a545..000000000
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_secret_activity.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/drawer_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <fragment
- android:id="@+id/key_list_secret_fragment"
- android:name="org.sufficientlysecure.keychain.ui.KeyListSecretFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="16dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:scrollbarStyle="outsideOverlay" />
- </FrameLayout>
-
- <include layout="@layout/drawer_list" />
-
-</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml
deleted file mode 100644
index 1ed86f730..000000000
--- a/OpenPGP-Keychain/src/main/res/layout/key_list_secret_item.xml
+++ /dev/null
@@ -1,32 +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="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingLeft="8dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:singleLine="true">
-
- <TextView
- android:id="@+id/mainUserId"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Main User ID"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true" />
-
- <TextView
- android:id="@+id/mainUserIdRest"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&lt;user@example.com>"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_below="@+id/mainUserId"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true" />
-
-</RelativeLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml b/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml
index 058a43eaf..950978a0e 100644
--- a/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml
@@ -13,7 +13,7 @@
<EditText
android:id="@+id/server"
- android:layout_width="match_parent"
+ android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textUri" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml b/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml
index c162a6e28..6031bf7c7 100644
--- a/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
diff --git a/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml b/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml
index 4a09e4240..eddbe3cbf 100644
--- a/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml
@@ -14,7 +14,7 @@
android:orientation="horizontal" >
<RelativeLayout
- android:layout_width="wrap_content"
+ android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_marginBottom="6sp"
android:layout_marginLeft="16sp"
diff --git a/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml b/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml
index 2bdd231ee..ae523762c 100644
--- a/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml
@@ -6,7 +6,9 @@
android:paddingRight="16dp"
android:stretchColumns="1" >
- <TableRow>
+ <TableRow
+ android:layout_marginBottom="5dip"
+ >
<TextView
android:id="@+id/passphrase_label_passphrase"
@@ -24,7 +26,9 @@
android:padding="4dp" />
</TableRow>
- <TableRow>
+ <TableRow
+ android:layout_marginBottom="10dip"
+ >
<TextView
android:id="@+id/passphrase_label_passphrase_again"
diff --git a/OpenPGP-Keychain/src/main/res/layout/select_key_item.xml b/OpenPGP-Keychain/src/main/res/layout/select_key_item.xml
index bbfe17c44..08c161ec6 100644
--- a/OpenPGP-Keychain/src/main/res/layout/select_key_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/select_key_item.xml
@@ -25,7 +25,7 @@
android:id="@+id/mainUserId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Main User ID"
+ android:text="@string/label_main_user_id"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
diff --git a/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml b/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml
index 5337433c6..a18ce46fc 100644
--- a/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/select_public_key_activity.xml
@@ -4,16 +4,8 @@
android:layout_height="match_parent"
android:layout_centerHorizontal="true" >
- <EditText
- android:id="@+id/select_public_key_search"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/menu_search"
- android:drawableLeft="@drawable/ic_action_search"/>
-
<FrameLayout
android:id="@+id/select_public_key_fragment_container"
- android:layout_below="@id/select_public_key_search"
android:layout_width="match_parent"
android:layout_height="match_parent" />
diff --git a/OpenPGP-Keychain/src/main/res/layout/select_secret_key_layout_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/select_secret_key_layout_fragment.xml
index 4a3cd3d28..408c0c54e 100644
--- a/OpenPGP-Keychain/src/main/res/layout/select_secret_key_layout_fragment.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/select_secret_key_layout_fragment.xml
@@ -3,7 +3,7 @@
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal" >
+ android:orientation="horizontal">
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/select_secret_key_select_key_button"
@@ -25,31 +25,54 @@
android:layout_marginLeft="4dp"
android:layout_marginTop="4dp"
android:orientation="vertical"
- android:paddingLeft="16dp" >
+ android:paddingLeft="4dp">
<!-- Has been made focusable to display error messages with setError -->
-
<TextView
android:id="@+id/select_secret_key_user_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:ellipsize="end"
+ android:layout_gravity="left"
android:focusable="true"
android:focusableInTouchMode="true"
android:singleLine="true"
- android:text="@string/api_settings_no_key"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:layout_marginRight="5dip"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/select_secret_key_user_id_rest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="right"
+ android:layout_gravity="left"
android:ellipsize="end"
android:singleLine="true"
+ android:layout_marginRight="5dip"
android:text=""
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:visibility="gone"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:paddingLeft="10dp" />
+
+ <TextView
+ android:id="@+id/select_secret_key_master_key_hex"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:visibility="gone"
+ android:layout_marginRight="15dip" />
+
+ <TextView
+ android:id="@+id/no_key_selected"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/api_settings_no_key"
+ android:layout_marginTop="15dp" />
+
+
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_delete_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_delete_fragment.xml
new file mode 100644
index 000000000..ef31f7690
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_delete_fragment.xml
@@ -0,0 +1,38 @@
+<?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">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/mainMessage"
+ android:layout_margin="4dp"
+ android:textAppearance="?android:textAppearanceMedium" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:weightSum="1"
+ android:id="@+id/deleteSecretKeyView">
+
+ <CheckBox
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.1"
+ android:layout_margin="4dp"
+ android:id="@+id/checkDeleteSecret" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:textAppearance="?android:textAppearanceMedium"
+ android:layout_weight="0.9"
+ android:text="@string/secret_key_delete_text" />
+
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml
index c44835bb0..aecedc39b 100644
--- a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml
@@ -4,8 +4,7 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="8dip"
- android:paddingRight="3dip"
- android:singleLine="true" >
+ android:paddingRight="3dip" >
<ImageView
android:id="@+id/ic_masterKey"
@@ -15,31 +14,54 @@
android:paddingRight="6dip"
android:src="@drawable/key_small" />
- <TextView
- android:id="@+id/keyId"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="5dip"
- android:text="Key ID"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:typeface="monospace" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="2dip"
+ android:paddingTop="2dip" >
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/keyId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="2dip"
+ android:text="@string/label_key_id"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:typeface="monospace" />
- <TextView
- android:id="@+id/keyDetails"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="(RSA, 1024bit)"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ <TextView
+ android:id="@+id/keyDetails"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:text="(RSA, 1024bit)"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </LinearLayout>
+ <TextView
+ android:id="@+id/keyExpiry"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:text="@string/label_expiry"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </LinearLayout>
<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:gravity="right"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:gravity="right"
android:paddingBottom="2dip"
android:paddingTop="2dip" >
+ <ImageView android:id="@+id/ic_revokedKey"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/revoked_key_small"/>
<ImageView
android:id="@+id/ic_certifyKey"
android:layout_width="wrap_content"
@@ -59,4 +81,4 @@
android:src="@drawable/signed_small" />
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
index 055687183..adbdb98dd 100644
--- a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
@@ -92,7 +92,7 @@
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
- android:stretchColumns="1">
+ android:shrinkColumns="1">
<TableRow>
@@ -130,6 +130,25 @@
android:text="" />
</TableRow>
+ <TableRow
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/tableRow">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="10dip"
+ android:text="@string/label_fingerprint" />
+
+ <TextView
+ android:id="@+id/fingerprint"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:typeface="monospace" />
+ </TableRow>
+
<TableRow>
<TextView
@@ -167,10 +186,10 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingRight="10dip"
- android:text="@string/label_fingerprint" />
+ android:text="@string/label_secret_key" />
<TextView
- android:id="@+id/fingerprint"
+ android:id="@+id/secret_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:typeface="monospace" />
@@ -212,6 +231,17 @@
android:text="@string/section_actions" />
<com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_edit"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:layout_marginBottom="10dp"
+ android:text="@string/key_view_action_edit"
+ bootstrapbutton:bb_icon_left="fa-key"
+ bootstrapbutton:bb_type="info"
+ android:visibility="gone" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/action_encrypt"
android:layout_width="match_parent"
android:layout_height="60dp"
@@ -221,6 +251,17 @@
bootstrapbutton:bb_icon_left="fa-lock"
bootstrapbutton:bb_type="info" />
+
+ <com.beardedhen.androidbootstrap.BootstrapButton
+ android:id="@+id/action_certify"
+ android:layout_width="match_parent"
+ android:layout_height="60dp"
+ android:padding="4dp"
+ android:layout_marginBottom="10dp"
+ android:text="@string/key_view_action_certify"
+ bootstrapbutton:bb_icon_left="fa-pencil"
+ bootstrapbutton:bb_type="info" />
+
</LinearLayout>
-</ScrollView> \ No newline at end of file
+</ScrollView>
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml
index 508d080a6..2e8cfeb04 100644
--- a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml
@@ -2,15 +2,44 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ android:orientation="horizontal"
android:paddingRight="3dip"
android:singleLine="true">
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/checkBox" />
+
<TextView
- android:id="@+id/userId"
+ android:id="@+id/rank"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="User ID"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="0"
+ android:paddingLeft="10dp"
+ android:paddingRight="10dp"
+ android:layout_gravity="center_vertical" />
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/userId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/user_id_no_name"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <TextView
+ android:id="@+id/address"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/label_email"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:paddingLeft="10dp" />
+ </LinearLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenPGP-Keychain/src/main/res/menu/api_account_settings.xml b/OpenPGP-Keychain/src/main/res/menu/api_account_settings.xml
new file mode 100644
index 000000000..d08fc7f42
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/menu/api_account_settings.xml
@@ -0,0 +1,14 @@
+<?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_account_settings_delete"
+ android:title="@string/api_settings_delete_account"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_account_settings_cancel"
+ android:title="@string/api_settings_cancel"
+ app:showAsAction="never" />
+
+</menu> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list.xml b/OpenPGP-Keychain/src/main/res/menu/key_list.xml
new file mode 100644
index 000000000..10223522c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/menu/key_list.xml
@@ -0,0 +1,38 @@
+<?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_key_list_import"
+ app:showAsAction="ifRoom|withText"
+ android:icon="@drawable/ic_action_add_person"
+ android:title="@string/menu_import" />
+
+ <item
+ android:id="@+id/menu_key_list_search"
+ android:title="@string/menu_search"
+ android:icon="@drawable/ic_action_search"
+ app:actionViewClass="android.support.v7.widget.SearchView"
+ app:showAsAction="collapseActionView|ifRoom" />
+
+ <item
+ android:id="@+id/menu_key_list_create"
+ app:showAsAction="never"
+ android:title="@string/menu_create_key" />
+
+ <item
+ android:id="@+id/menu_key_list_create_expert"
+ app:showAsAction="never"
+ android:title="@string/menu_create_key_expert" />
+
+ <item
+ android:id="@+id/menu_key_list_export"
+ app:showAsAction="never"
+ android:title="@string/menu_export_keys" />
+
+ <item
+ android:id="@+id/menu_key_list_secret_export"
+ app:showAsAction="never"
+ android:title="@string/menu_export_secret_keys" />
+
+</menu>
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_public_multi.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_multi.xml
index d30ee5e8f..db709052f 100644
--- a/OpenPGP-Keychain/src/main/res/menu/key_list_public_multi.xml
+++ b/OpenPGP-Keychain/src/main/res/menu/key_list_multi.xml
@@ -2,16 +2,20 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/menu_key_list_public_multi_select_all"
+ android:id="@+id/menu_key_list_multi_select_all"
android:icon="@drawable/ic_action_select_all"
android:title="@string/menu_select_all" />
<item
- android:id="@+id/menu_key_list_public_multi_encrypt"
+ android:id="@+id/menu_key_list_multi_export"
+ android:icon="@drawable/ic_action_import_export"
+ android:title="@string/menu_export_key" />
+ <item
+ android:id="@+id/menu_key_list_multi_encrypt"
android:icon="@drawable/ic_action_secure"
android:title="@string/menu_encrypt_to" />
<item
- android:id="@+id/menu_key_list_public_multi_delete"
+ android:id="@+id/menu_key_list_multi_delete"
android:icon="@drawable/ic_action_discard"
android:title="@string/menu_delete_key" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml
deleted file mode 100644
index 35a8f3926..000000000
--- a/OpenPGP-Keychain/src/main/res/menu/key_list_public.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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_key_list_public_import"
- app:showAsAction="always|withText"
- android:icon="@drawable/ic_action_add_person"
- android:title="@string/menu_import" />
- <item
- android:id="@+id/menu_key_list_public_export"
- app:showAsAction="never"
- android:title="@string/menu_export_keys" />
- <item
- android:id="@+id/menu_key_list_public_search"
- android:title="@string/menu_search"
- android:icon="@drawable/ic_action_search"
- app:actionViewClass="android.support.v7.widget.SearchView"
- app:showAsAction="ifRoom" />
-</menu> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_secret.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_secret.xml
deleted file mode 100644
index 18a97ed72..000000000
--- a/OpenPGP-Keychain/src/main/res/menu/key_list_secret.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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_key_list_secret_create"
- app:showAsAction="always|withText"
- android:title="@string/menu_create_key" />
- <item
- android:id="@+id/menu_key_list_secret_create_expert"
- app:showAsAction="never"
- android:title="@string/menu_create_key_expert" />
- <item
- android:id="@+id/menu_key_list_secret_import"
- app:showAsAction="never"
- android:title="@string/menu_import" />
- <item
- android:id="@+id/menu_key_list_secret_export"
- app:showAsAction="never"
- android:title="@string/menu_export_keys" />
-
-</menu> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml
deleted file mode 100644
index a3375c7e8..000000000
--- a/OpenPGP-Keychain/src/main/res/menu/key_list_secret_multi.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item
- android:id="@+id/menu_key_list_public_multi_select_all"
- android:icon="@drawable/ic_action_select_all"
- android:title="@string/menu_select_all" />
- <item
- android:id="@+id/menu_key_list_public_multi_delete"
- android:icon="@drawable/ic_action_discard"
- android:title="@string/menu_delete_key" />
-
-</menu> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_view.xml b/OpenPGP-Keychain/src/main/res/menu/key_view.xml
index 59247221a..105368cbb 100644
--- a/OpenPGP-Keychain/src/main/res/menu/key_view.xml
+++ b/OpenPGP-Keychain/src/main/res/menu/key_view.xml
@@ -5,7 +5,7 @@
<item
android:id="@+id/menu_key_view_share"
android:icon="@drawable/ic_action_share"
- app:showAsAction="always"
+ app:showAsAction="ifRoom"
android:title="@string/menu_share">
<menu>
<item
@@ -52,7 +52,7 @@
android:id="@+id/menu_key_keyserver"
android:icon="@drawable/ic_action_import_export"
app:showAsAction="always"
- android:title="@string/menu_share">
+ android:title="@string/menu_key_server">
<menu>
<item
android:id="@+id/menu_key_view_update"
diff --git a/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_about.html b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_about.html
new file mode 100644
index 000000000..99977f75d
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_about.html
@@ -0,0 +1,49 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
+<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
+<p>Licence: GPLv3+</p>
+
+<h2>Developers OpenKeychain</h2>
+<ul>
+<li>Dominik Schürmann (Hlavní vývojář)</li>
+<li>Ash Hughes (crypto patches)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (UI)</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
+</ul>
+<h2>Developers APG 1.x</h2>
+<ul>
+<li>Thialfihar (Lead developer)</li>
+<li>'Senecaso' (QRCode, sign key, upload key)</li>
+<li>Markus Doits</li>
+</ul>
+<h2>Libraries</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_changelog.html
new file mode 100644
index 000000000..1136deba6
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_changelog.html
@@ -0,0 +1,129 @@
+<html>
+<head></head>
+<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
+<h2>2.3</h2>
+<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
+<li>fix crash on keys with empty user ids</li>
+<li>fix crash and empty lists when coming back from signing screen</li>
+<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
+<li>fix upload of key from signing screen</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>new design with navigation drawer</li>
+<li>new public key list design</li>
+<li>new public key view</li>
+<li>bug fixes for importing of keys</li>
+<li>key cross-certification (thanks to Ash Hughes)</li>
+<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
+<li>first version with new languages (thanks to the contributors on Transifex)</li>
+<li>sharing of keys via QR Codes fixed and improved</li>
+<li>package signature verification for API</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>API Updates, preparation for K-9 Mail integration</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>lots of bug fixes</li>
+<li>new API for developers</li>
+<li>PRNG bug fix by Google</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>complete redesign</li>
+<li>share public keys via qr codes, nfc beam</li>
+<li>sign keys</li>
+<li>upload keys to server</li>
+<li>fixes import issues</li>
+<li>new AIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>basic keyserver support</li>
+<li>app2sd</li>
+<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
+<li>bugfixes</li>
+<li>optimizations</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>fixed problem with signature verification of texts with trailing newline</li>
+<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>account adding crash on Froyo fixed</li>
+<li>secure file deletion</li>
+<li>option to delete key file after import</li>
+<li>stream encryption/decryption (gallery, etc.)</li>
+<li>new options (language, force v3 signatures)</li>
+<li>interface changes</li>
+<li>bugfixes</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>German and Italian translation</li>
+<li>much smaller package, due to reduced BC sources</li>
+<li>new preferences GUI</li>
+<li>layout adjustment for localization</li>
+<li>signature bugfix</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>fixed another crash caused by some SDK bug with query builder</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>fixed crashes during encryption/signing and possibly key export</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>filterable key lists</li>
+<li>smarter pre-selection of encryption keys</li>
+<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
+<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>GMail account listing was broken in 1.0.0, fixed again</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
+<li>support of more file managers (including ASTRO)</li>
+<li>Slovenian translation</li>
+<li>new database, much faster, less memory usage</li>
+<li>defined Intents and content provider for other apps</li>
+<li>bugfixes</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_nfc_beam.html
new file mode 100644
index 000000000..88492731c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>How to receive keys</h2>
+<ol>
+<li>Go to your partners contacts and open the contact you want to share.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
+<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the your device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_start.html b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_start.html
new file mode 100644
index 000000000..0e60c17a7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>Getting started</h2>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
+
+<h2>I found a bug in OpenKeychain!</h2>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/nfc_beam_share.html
new file mode 100644
index 000000000..083e055c7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-cs-rCZ/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the other person’s device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_about.html b/OpenPGP-Keychain/src/main/res/raw-de/help_about.html
index 37d4193f7..7dc0ee7d9 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (crypto patches)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Entwickler APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Leitender Entwickler)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QR-Code, Schlüssel signtieren, Schlüssel hochladen)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Bibliotheken</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache Lizenz v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Bibliothek</a> (Apache Lizenz v2)</li>
-<li>Icons von <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike Lizenz 3.0)</li>
-<li>Icons von <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html
index 1197869b5..13b210fcd 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
@@ -8,7 +29,7 @@
<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
<li>querying keyservers directly from the import screen</li>
<li>fix layout and dialog style on Android 2.2-3.0</li>
-<li>fix crash on keys with empty user ids</li>
+<li>Absturz bei leeren Nutzer IDs behoben </li>
<li>fix crash and empty lists when coming back from signing screen</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
<li>fix upload of key from signing screen</li>
@@ -38,15 +59,15 @@
<h2>2.0</h2>
<ul>
<li>Komlett neu designd</li>
-<li>share public keys via qr codes, nfc beam</li>
+<li>Öffentliche Schlüssel teilen via QR Code, NFC Beam</li>
<li>Schlüssel signieren</li>
<li>Schlüssel auf den Server hochladen</li>
-<li>fixes import issues</li>
+<li>Importprobleme behoben</li>
<li>new AIDL API</li>
</ul>
<h2>1.0.8</h2>
<ul>
-<li>basic keyserver support</li>
+<li>Grundlegende Schlüsselserverunterstützung</li>
<li>app2sd</li>
<li>mehr Auswahlmöglichkeiten für den Passwortcache: 1, 2, 4, 8, Stunden</li>
<li>Übersetzungen: norwegisch (Danke, Sander Danielsen), chinesisch (danke, Zhang Fredrick)</li>
@@ -98,8 +119,8 @@
<h2>1.0.0</h2>
<ul>
<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
-<li>support of more file managers (including ASTRO)</li>
-<li>Slovenian translation</li>
+<li>Unterstützung von mehr Filemanagern (einschließlich ASTRO)</li>
+<li>Slowenische Übersetzung</li>
<li>Neue Datenbank, viel schneller, weniger Speicherbedarf</li>
<li>defined Intents and content provider for other apps</li>
<li>Fehlerbehebungen</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_start.html b/OpenPGP-Keychain/src/main/res/raw-de/help_start.html
index d2735f739..7a652682e 100644
--- a/OpenPGP-Keychain/src/main/res/raw-de/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-de/help_start.html
@@ -1,15 +1,15 @@
<html>
<head></head>
<body>
-<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<h2>Los gehts</h2>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>Ich habe einen Fehler in OpenKeychain gefunden!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
-<h2>Contribute</h2>
+<h2>Unterstützen</h2>
<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Übersetzungen</h2>
diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_about.html b/OpenPGP-Keychain/src/main/res/raw-el/help_about.html
new file mode 100644
index 000000000..ae7e16aae
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-el/help_about.html
@@ -0,0 +1,49 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
+<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
+<p>License: GPLv3+</p>
+
+<h2>Developers OpenKeychain</h2>
+<ul>
+<li>Dominik Schürmann (Lead developer)</li>
+<li>Ash Hughes (crypto patches)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (UI)</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
+</ul>
+<h2>Developers APG 1.x</h2>
+<ul>
+<li>Thialfihar (Lead developer)</li>
+<li>'Senecaso' (QRCode, sign key, upload key)</li>
+<li>Markus Doits</li>
+</ul>
+<h2>Libraries</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-el/help_changelog.html
new file mode 100644
index 000000000..1136deba6
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-el/help_changelog.html
@@ -0,0 +1,129 @@
+<html>
+<head></head>
+<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
+<h2>2.3</h2>
+<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
+<li>fix crash on keys with empty user ids</li>
+<li>fix crash and empty lists when coming back from signing screen</li>
+<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
+<li>fix upload of key from signing screen</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>new design with navigation drawer</li>
+<li>new public key list design</li>
+<li>new public key view</li>
+<li>bug fixes for importing of keys</li>
+<li>key cross-certification (thanks to Ash Hughes)</li>
+<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
+<li>first version with new languages (thanks to the contributors on Transifex)</li>
+<li>sharing of keys via QR Codes fixed and improved</li>
+<li>package signature verification for API</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>API Updates, preparation for K-9 Mail integration</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>lots of bug fixes</li>
+<li>new API for developers</li>
+<li>PRNG bug fix by Google</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>complete redesign</li>
+<li>share public keys via qr codes, nfc beam</li>
+<li>sign keys</li>
+<li>upload keys to server</li>
+<li>fixes import issues</li>
+<li>new AIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>basic keyserver support</li>
+<li>app2sd</li>
+<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
+<li>bugfixes</li>
+<li>optimizations</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>fixed problem with signature verification of texts with trailing newline</li>
+<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>account adding crash on Froyo fixed</li>
+<li>secure file deletion</li>
+<li>option to delete key file after import</li>
+<li>stream encryption/decryption (gallery, etc.)</li>
+<li>new options (language, force v3 signatures)</li>
+<li>interface changes</li>
+<li>bugfixes</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>German and Italian translation</li>
+<li>much smaller package, due to reduced BC sources</li>
+<li>new preferences GUI</li>
+<li>layout adjustment for localization</li>
+<li>signature bugfix</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>fixed another crash caused by some SDK bug with query builder</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>fixed crashes during encryption/signing and possibly key export</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>filterable key lists</li>
+<li>smarter pre-selection of encryption keys</li>
+<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
+<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>GMail account listing was broken in 1.0.0, fixed again</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
+<li>support of more file managers (including ASTRO)</li>
+<li>Slovenian translation</li>
+<li>new database, much faster, less memory usage</li>
+<li>defined Intents and content provider for other apps</li>
+<li>bugfixes</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-el/help_nfc_beam.html
new file mode 100644
index 000000000..88492731c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-el/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>How to receive keys</h2>
+<ol>
+<li>Go to your partners contacts and open the contact you want to share.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
+<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the your device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_start.html b/OpenPGP-Keychain/src/main/res/raw-el/help_start.html
new file mode 100644
index 000000000..0e60c17a7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-el/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>Getting started</h2>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
+
+<h2>I found a bug in OpenKeychain!</h2>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-el/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-el/nfc_beam_share.html
new file mode 100644
index 000000000..083e055c7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-el/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the other person’s device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html
index 863aeee58..ae7e16aae 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (crypto patches)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Developers APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Lead developer)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QRCode, sign key, upload key)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Libraries</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html
index abf660ba8..1136deba6 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html
index 3a6443a2f..0e60c17a7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es-rCO/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/help_about.html b/OpenPGP-Keychain/src/main/res/raw-es/help_about.html
index 95189425d..7a4f61127 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (Parches cryptográficos)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Desarrolladores de APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Desarrollador principal)</li>
+<li>Thialfihar (Desarrollador principal)</li>
<li>'Senecaso' (Código QR, clave de firma, carga de clave)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Librerías</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencia Apache v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Librería Android AppMsg</a> (Licencia Apache v2)</li>
-<li>Icons de <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Compartir-Igual licencia 3.0)</li>
-<li>Iconos de <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Dominio Público)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html
index dfb51dc81..b776b3534 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>elimina la exportación innecesaria de claves públicas cuando se exporta la clave secreta (gracias a Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-es/help_start.html b/OpenPGP-Keychain/src/main/res/raw-es/help_start.html
index 2907bbc99..d56399ef0 100644
--- a/OpenPGP-Keychain/src/main/res/raw-es/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-es/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Primeros pasos</h2>
-<p>Primero necesitas un par de claves personales. Crea una a través del menú "Mis claves" o importa un par de claves ya existentes a través de "Importar claves". Después, puedes descargar las claves de tus amigos o intercambiarlas a través de códigos QR o NFC.</p>
+<p>Primero necesitas un par de claves personales. Crea una a través de las opciones del menú "Contactos" o importa un par de claves ya existentes a través de "Importar claves". Después, puedes descargar las claves de tus amigos o intercambiarlas a través de códigos QR o NFC.</p>
<p>Es recomendable que instales <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> para una mejor selección de archivos y <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> para escanear los códigos QR generados. Pulsando en los enlaces se abrirá Google Play o F-Droid.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-et/help_about.html b/OpenPGP-Keychain/src/main/res/raw-et/help_about.html
new file mode 100644
index 000000000..ae7e16aae
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-et/help_about.html
@@ -0,0 +1,49 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
+<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
+<p>License: GPLv3+</p>
+
+<h2>Developers OpenKeychain</h2>
+<ul>
+<li>Dominik Schürmann (Lead developer)</li>
+<li>Ash Hughes (crypto patches)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (UI)</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
+</ul>
+<h2>Developers APG 1.x</h2>
+<ul>
+<li>Thialfihar (Lead developer)</li>
+<li>'Senecaso' (QRCode, sign key, upload key)</li>
+<li>Markus Doits</li>
+</ul>
+<h2>Libraries</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-et/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-et/help_changelog.html
new file mode 100644
index 000000000..1136deba6
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-et/help_changelog.html
@@ -0,0 +1,129 @@
+<html>
+<head></head>
+<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
+<h2>2.3</h2>
+<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
+<li>fix crash on keys with empty user ids</li>
+<li>fix crash and empty lists when coming back from signing screen</li>
+<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
+<li>fix upload of key from signing screen</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>new design with navigation drawer</li>
+<li>new public key list design</li>
+<li>new public key view</li>
+<li>bug fixes for importing of keys</li>
+<li>key cross-certification (thanks to Ash Hughes)</li>
+<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
+<li>first version with new languages (thanks to the contributors on Transifex)</li>
+<li>sharing of keys via QR Codes fixed and improved</li>
+<li>package signature verification for API</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>API Updates, preparation for K-9 Mail integration</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>lots of bug fixes</li>
+<li>new API for developers</li>
+<li>PRNG bug fix by Google</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>complete redesign</li>
+<li>share public keys via qr codes, nfc beam</li>
+<li>sign keys</li>
+<li>upload keys to server</li>
+<li>fixes import issues</li>
+<li>new AIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>basic keyserver support</li>
+<li>app2sd</li>
+<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
+<li>bugfixes</li>
+<li>optimizations</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>fixed problem with signature verification of texts with trailing newline</li>
+<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>account adding crash on Froyo fixed</li>
+<li>secure file deletion</li>
+<li>option to delete key file after import</li>
+<li>stream encryption/decryption (gallery, etc.)</li>
+<li>new options (language, force v3 signatures)</li>
+<li>interface changes</li>
+<li>bugfixes</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>German and Italian translation</li>
+<li>much smaller package, due to reduced BC sources</li>
+<li>new preferences GUI</li>
+<li>layout adjustment for localization</li>
+<li>signature bugfix</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>fixed another crash caused by some SDK bug with query builder</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>fixed crashes during encryption/signing and possibly key export</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>filterable key lists</li>
+<li>smarter pre-selection of encryption keys</li>
+<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
+<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>GMail account listing was broken in 1.0.0, fixed again</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
+<li>support of more file managers (including ASTRO)</li>
+<li>Slovenian translation</li>
+<li>new database, much faster, less memory usage</li>
+<li>defined Intents and content provider for other apps</li>
+<li>bugfixes</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-et/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-et/help_nfc_beam.html
new file mode 100644
index 000000000..88492731c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-et/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>How to receive keys</h2>
+<ol>
+<li>Go to your partners contacts and open the contact you want to share.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
+<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the your device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-et/help_start.html b/OpenPGP-Keychain/src/main/res/raw-et/help_start.html
new file mode 100644
index 000000000..0e60c17a7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-et/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>Getting started</h2>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
+
+<h2>I found a bug in OpenKeychain!</h2>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-et/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-et/nfc_beam_share.html
new file mode 100644
index 000000000..083e055c7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-et/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the other person’s device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_about.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_about.html
new file mode 100644
index 000000000..ae7e16aae
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_about.html
@@ -0,0 +1,49 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
+<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
+<p>License: GPLv3+</p>
+
+<h2>Developers OpenKeychain</h2>
+<ul>
+<li>Dominik Schürmann (Lead developer)</li>
+<li>Ash Hughes (crypto patches)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (UI)</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
+</ul>
+<h2>Developers APG 1.x</h2>
+<ul>
+<li>Thialfihar (Lead developer)</li>
+<li>'Senecaso' (QRCode, sign key, upload key)</li>
+<li>Markus Doits</li>
+</ul>
+<h2>Libraries</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_changelog.html
new file mode 100644
index 000000000..1136deba6
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_changelog.html
@@ -0,0 +1,129 @@
+<html>
+<head></head>
+<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
+<h2>2.3</h2>
+<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
+<li>fix crash on keys with empty user ids</li>
+<li>fix crash and empty lists when coming back from signing screen</li>
+<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
+<li>fix upload of key from signing screen</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>new design with navigation drawer</li>
+<li>new public key list design</li>
+<li>new public key view</li>
+<li>bug fixes for importing of keys</li>
+<li>key cross-certification (thanks to Ash Hughes)</li>
+<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
+<li>first version with new languages (thanks to the contributors on Transifex)</li>
+<li>sharing of keys via QR Codes fixed and improved</li>
+<li>package signature verification for API</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>API Updates, preparation for K-9 Mail integration</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>lots of bug fixes</li>
+<li>new API for developers</li>
+<li>PRNG bug fix by Google</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>complete redesign</li>
+<li>share public keys via qr codes, nfc beam</li>
+<li>sign keys</li>
+<li>upload keys to server</li>
+<li>fixes import issues</li>
+<li>new AIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>basic keyserver support</li>
+<li>app2sd</li>
+<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
+<li>bugfixes</li>
+<li>optimizations</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>fixed problem with signature verification of texts with trailing newline</li>
+<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>account adding crash on Froyo fixed</li>
+<li>secure file deletion</li>
+<li>option to delete key file after import</li>
+<li>stream encryption/decryption (gallery, etc.)</li>
+<li>new options (language, force v3 signatures)</li>
+<li>interface changes</li>
+<li>bugfixes</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>German and Italian translation</li>
+<li>much smaller package, due to reduced BC sources</li>
+<li>new preferences GUI</li>
+<li>layout adjustment for localization</li>
+<li>signature bugfix</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>fixed another crash caused by some SDK bug with query builder</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>fixed crashes during encryption/signing and possibly key export</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>filterable key lists</li>
+<li>smarter pre-selection of encryption keys</li>
+<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
+<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>GMail account listing was broken in 1.0.0, fixed again</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
+<li>support of more file managers (including ASTRO)</li>
+<li>Slovenian translation</li>
+<li>new database, much faster, less memory usage</li>
+<li>defined Intents and content provider for other apps</li>
+<li>bugfixes</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_nfc_beam.html
new file mode 100644
index 000000000..88492731c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>How to receive keys</h2>
+<ol>
+<li>Go to your partners contacts and open the contact you want to share.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
+<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the your device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_start.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_start.html
new file mode 100644
index 000000000..93a305796
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>شروع کار</h2>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
+
+<h2>I found a bug in OpenKeychain!</h2>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
+
+<h2>هم بخشی کردن</h2>
+<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>ترجمه ها</h2>
+<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/nfc_beam_share.html
new file mode 100644
index 000000000..083e055c7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the other person’s device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html b/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html
index 3cbbce4d5..00370c77e 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (correctif crypto)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar « kalkin » Gadimov (interface utilisateur)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Les développeurs d'APG 1.x</h2>
<ul>
-<li>« Thialfihar (développeur principal)</li>
+<li>Thialfihar (développeur principal)</li>
<li>« Senecaso » (Code QR, signer/téléverser la clef)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Bibliothèques</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licence Apache v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Bibliothèque Android AppMsg</a> (Licence Apache v2)</li>
-<li>Icônes du <a href="http://rrze-icon-set.berlios.de/">jeu d'icônes RRZE</a> (Licence Creative Commons Paternité - Partage des Conditions Initiales à l'Identique 3.0)</li>
-<li>Icônes du <a href="http://tango.freedesktop.org/">jeu d'icônes Tango</a> (domaine public)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html
index c86c4a465..56a35d70e 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>supprimer l'exportation non nécessaire des clefs publiques lors de l'exportation d'une clef secrète</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html b/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html
index 0c1610f0c..ddaac44b1 100644
--- a/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-fr/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Commencer</h2>
-<p>Vous avez d'abord besoin d'une paire de clefs personelles. Créez-en une avec l'option du menu « Mes clefs » ou importez des paires de clefs existantes avec « Importer des clefs ». Ensuite vous pouvez télécharger les clefs de vos amis, ou les échanger par codes QR ou NFC.</p>
+<p>Il vous faut d'abord une paire de clefs personnelles. Créez-en une avec le menu des options dans « Contacts » ou importez des paires de clefs existantes avec « Importer des clefs ». Ensuite vous pouvez télécharger les clefs de vos amis, ou les échanger par codes QR ou NFC.</p>
<p>Il vous est recommendé d'installer le <a href="market://details?id=org.openintents.filemanager">gestionnaire de fichiers OI</a> pour sa fonction améliorée de séléction des fichiers et le <a href="market://details?id=com.google.zxing.client.android">lecteur de codes à barres</a> pour balayer les codes QR générés. Cliquer sur les liens ouvrira Google Play Store ou F-Droid pour l'installation.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html
index ba0676f3e..917c7cc49 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (Patch crittografia)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (Interfaccia Utente)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Sviluppatori APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Capo Sviluppatore)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QRCode, firma chiavi, caricamento chiavi)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Librerie</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licenza Apache v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Licenza Apache v2)</li>
-<li>Icone da <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Licenza Creative Commons Attribution Share-Alike 3.0)</li>
-<li>Icone da <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Pubblico Dominio)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html
index 050d2c9ef..de167f870 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>rimossa esportazione non necessaria delle chiavi pubbliche quando si esportano le chiavi private (grazie a Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html
index 4eadd82fc..7255d70bb 100644
--- a/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-it-rIT/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Per iniziare</h2>
-<p>Per prima cosa hai bisogno di un paio di chiavi personali. Creane una tramite i menu di opzione sotto 'Mie Chiavi' o importane di esistenti attraverso "Importa Chiavi". Dopodiche' puoi scaricare le chiavi dei tuoi amici o scambiarle tramite Codici QR o NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>Si raccomanda di installare <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> per una migliore selezione dei file e <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> per scansionare i codici QR. I collegamenti verranno aperti in Google Play Store o F-Droid per l'installazione.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/help_about.html b/OpenPGP-Keychain/src/main/res/raw-ja/help_about.html
index 206fc9f8d..e60add867 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ja/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (暗号関係パッチ提供)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>APG 1.xの開発者達</h2>
<ul>
-<li>'Thialfihar' (主任開発者)</li>
+<li>Thialfihar (主任開発者)</li>
<li>'Senecaso' (QRコード, 鍵署名, 鍵アップロード関係)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>ライブラリ</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (パブリックドメイン)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html
index 4878a3b55..e60c7f63f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>秘密鍵のエクスポート時における必要でない公開鍵のエクスポートの削除 (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ja/help_start.html b/OpenPGP-Keychain/src/main/res/raw-ja/help_start.html
index 9764e876a..0a92042b1 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ja/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ja/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>入門</h2>
-<p>最初にあなたの個人用鍵ペアが必要になります。オプションメニューの"自分の鍵"で生成するか、"鍵のインポート"から既存の鍵ペアをインポートします。その後、あなたの友人の鍵をダウンロード、もしくはQRコードやNFCで交換します。</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>ファイルの選択を拡張するには<a href="market://details?id=org.openintents.filemanager">OI File Manager</a>、<a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a>を生成したQRコードのスキャンのため、それぞれのインストールを必要とします。 リンクをクリックして、Google Play Store上かF-Droidからインストールしてください。</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html
index 863aeee58..ae7e16aae 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (crypto patches)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Developers APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Lead developer)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QRCode, sign key, upload key)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Libraries</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html
index abf660ba8..1136deba6 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html
index 3a6443a2f..0e60c17a7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-nl-rNL/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pl/help_about.html b/OpenPGP-Keychain/src/main/res/raw-pl/help_about.html
new file mode 100644
index 000000000..a033c084a
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-pl/help_about.html
@@ -0,0 +1,49 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
+<p><a href="http://www.openkeychain.org">OpenKeychain</a> to implementacja OpenPGP na platformę Android.</p>
+<p>Licencja: GPLv3+</p>
+
+<h2>Deweloperzy OpenKeychain</h2>
+<ul>
+<li>Dominik Schürmann (Wiodący developer)</li>
+<li>Ash Hughes (łatki crypto)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (Interfejs Użytkownika)</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
+</ul>
+<h2>Deweloperzy APG 1.x</h2>
+<ul>
+<li>Thialfihar (Wiodący deweloper)</li>
+<li>'Senecaso' (kody QR, podpisy kluczy, wysyłanie kluczy)</li>
+<li>Markus Doits</li>
+</ul>
+<h2>Biblioteki</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Licencja Apache v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Licencja Apache v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licencja Apache v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (Licencja MIT)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Licencja Apache v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencja MIT X11)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencja Apache v2)</li>
+<li>
+<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Licencja Apache v2)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pl/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-pl/help_changelog.html
new file mode 100644
index 000000000..18ea0735e
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-pl/help_changelog.html
@@ -0,0 +1,129 @@
+<html>
+<head></head>
+<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
+<h2>2.3</h2>
+<ul>
+<li>usunięto zbędne eksportowanie kluczy publicznych przy eksportowaniu kluczy prywatnych (podziękowania dla Ash Hughes)</li>
+<li>naprawiono błąd z ustawianiem daty wygaśnięcia kluczy (podziękowania dla Ash Hugens)</li>
+<li>więcej wewnętrznych poprawek przy edytowaniu kluczy (podziękowania dla Ash Hughes)</li>
+<li>wysyłanie zapytań do serwera kluczy bezpośrednio z ekranu importu</li>
+<li>poprawiony wygląd interfejsu i okienek na Androidzie 2.2-3.0</li>
+<li>naprawiono awarię programu dla kluczy z pustym identyfikatorem użytkownika</li>
+<li>naprawiono awarię aplikacji przy powrocie z ekranu podpisywania</li>
+<li>Bouncy Castle (biblioteka kryptograficzna) zaktualizowana z wersji 1.47 do 1.50 i kompilowana ze źródeł</li>
+<li>naprawiony błąd przy wysyłaniu klucza z ekranu podpisywania</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>nowy wygląd z panelem nawigacji</li>
+<li>nowy wygląd listy kluczy publicznych</li>
+<li>nowy widok klucza publicznego</li>
+<li>naprawiono błędy związane z importowaniem kluczy</li>
+<li>krzyżowa certyfikacja kluczy (podziękowania dla Ash Hughes)</li>
+<li>hasła zapisane w UTF-8 są teraz prawidłowo obsługiwane (podziękowania dla Ash Hughes)</li>
+<li>pierwsza wersja z nowymi językami (podziękowania dla tłumaczy-wolontariuszy z Transifex)</li>
+<li>udostępnianie kluczy przez kody QR zostało poprawione i ulepszone</li>
+<li>weryfikacja podpisu paczki dla API</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>aktualizacje API, przygotowanie do integracji z K-9 Mail</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>wiele poprawek błędów</li>
+<li>nowe API dla programistów</li>
+<li>Naprawiono błąd generatora liczb losowych (PRNG), Google.</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>kompletna przebudowa</li>
+<li>udostępnianie kluczy publicznych przez kody QR oraz NFC</li>
+<li>możliwość podpisywania kluczem</li>
+<li>wysyłanie kluczy na serwer</li>
+<li>naprawiono problemy związane z importowaniem</li>
+<li>nowy AIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>podstawowa obsługa serwerów kluczy</li>
+<li>app2sd</li>
+<li>dodano więcej przedziałów czasowych zapamiętywania hasła: 1, 2, 4, 8 godzin</li>
+<li>tłumaczenia: norweski (podziękowania dla Sander Danielsen), chiński (podziękowania dla Zhang Fredrick)</li>
+<li>naprawione błędy</li>
+<li>usprawnienia</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>naprawiono problem z weryfikowaniem podpisu tekstów kończących się znakiem nowej linii</li>
+<li>dodano więcej przedziałów czasowych zapamiętywania hasła (20, 40, 60 minut)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>naprawiono błąd powodujący awarię aplikacji przy dodawaniu nowego konta na Androidzie 2.2 Froyo</li>
+<li>dodano bezpieczne usuwanie plików</li>
+<li>Dodano możliwość usuwania plików kluczy po zaimportowaniu</li>
+<li>możliwość strumieniowego szyfrowania/deszyfrowania (galeria i inne)</li>
+<li>nowe opcje (języki, wymuszanie podpisów v3)</li>
+<li>zmiany w interfejsie</li>
+<li>naprawione błędy</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>tłumaczenie na niemiecki i włoski</li>
+<li>znaczne zmniejszenie rozmiaru paczki, z powodu zredukowania źródeł BC</li>
+<li>nowy interfejs graficzny Właściwości</li>
+<li>usprawnienia wyglądu dla lokalizacji</li>
+<li>naprawa błędu z podpisami</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>naprawiono kolejny błąd powodujący awarię aplikacji, spowodowany przez jakąś usterkę w SDK przy budowaniu zapytań</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>naprawiono błąd w trakcie szyfrowania/podpisywania i prawdopodobnie eksportowania klucza</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>dodano możliwość filtrowania listy kluczy</li>
+<li>sprytniejsze automatyczne wybieranie kluczy szyfrujących</li>
+<li>dodano nowy sposób obsługi intencji "wyświetl" i "wyślij", umożliwia szyfrowanie/deszyfrowanie plików wprost z menadżera plików.</li>
+<li>poprawki i dodatkowe funkcje (podpowiedź wyboru klucza) dla K-9 Mail, nowe wydanie beta dostępne</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>wyświetlanie kont w GMailu było zepsute w 1.0.0, naprawiono je ponownie</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>integracja z K-9 Mail, APG obsługuje wersję beta K-9 Mail</li>
+<li>dodano wsparcie dla większej liczby menadżerów plików (włącznie z ASTRO)</li>
+<li>tłumaczenie na słoweński</li>
+<li>Wykorzystanie nowej bazy danych, która jest znacznie szybsza i mniej pamięciożerna</li>
+<li>zdefiniowano intecję i dostawców treści dla pozostałych aplikacji</li>
+<li>naprawione błędy</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pl/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-pl/help_nfc_beam.html
new file mode 100644
index 000000000..53db5e80c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-pl/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>Jak odbierać klucze</h2>
+<ol>
+<li>Wejdź do listy kontaktów Twojego partnera i otwórz kontakt, który chcesz przesłać.</li>
+<li>Przytrzymaj oba urządzenia plecami do siebie (powinny się niemal dotykać) i poczujesz wibrację.</li>
+<li>Po zakończeniu wibracji zobaczysz, że zawartość urządzenia partnera zamienia się w obiekt zbliżony do wizytówki, z animacją rodem ze Star Treka w tle.</li>
+<li>Dotknij wizytówkę, a jej zawartość zostanie wysłana na Twoje urządzenie.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pl/help_start.html b/OpenPGP-Keychain/src/main/res/raw-pl/help_start.html
new file mode 100644
index 000000000..e88a1ad6d
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-pl/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>Pierwsze kroki</h2>
+<p>Po pierwsze potrzebujesz swoją osobistą parę kluczy. Stwórz ją, korzystając z odpowiedniej opcji w sekcji "Kontakty" albo zainportuj istniejącą parę korzystając z sekcji "Inportuj klucze". Następnie możesz porać klucze Twoich znajomych lub wymieniać się z nimi za pośrednictwem kodów QR lub technologii NFC.</p>
+
+<p>Zalecana jest instalacja menadżera plików <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> w celu zapewnienia wygodniejszego wyboru plików oraz programu <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a>, który jest w stanie skanować wygenerowane kody QR. Kliknięcie na powyższe linki przekieruje Cię do sklepu Google Play / F-Droid.</p>
+
+<h2>Znalazłem błąd w OpenKeychain!</h2>
+<p>Zgłoś błąd korzystając z <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">systemu śledzenia błędów OpenKeychain</a>.</p>
+
+<h2>Wkład</h2>
+<p>Jeżeli chcesz pomóc nam rozwijać OpenKeychain jako programista, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">zapoznaj się z naszym małym poradnikiem na Githubie</a>.</p>
+
+<h2>Tłumaczenia</h2>
+<p>Pomóż przetłumaczyć OpenKeychain! Każdy może wziąć udział przez stronę <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain w serwisie Transifex</a>.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pl/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-pl/nfc_beam_share.html
new file mode 100644
index 000000000..f17e44079
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-pl/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>Upewnij się, że NFC (Near Field Communication, pol.: komunikacja bliskiego zasięgu) jest włączone. W tym celu wejdź w Ustawienia &gt; Inne &gt; NFC. Upewnij się również, że włączona jest funkcja Android Beam (znajduje się w tym samym miejscu).</li>
+<li>Przytrzymaj oba urządzenia plecami do siebie (powinny się niemal dotykać) i poczujesz wibrację.</li>
+<li>Po zakończeniu wibracji zobaczysz, że zawartość urządzenia partnera zamienia się w obiekt zbliżony do wizytówki, z animacją rodem ze Star Treka w tle.</li>
+<li>Dotknij wizytówkę, a jej zawartość zostanie wysłana na urządzenie drugiej osoby.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html
index 863aeee58..ae7e16aae 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (crypto patches)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Developers APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Lead developer)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QRCode, sign key, upload key)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Libraries</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html
index abf660ba8..1136deba6 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html
index 3a6443a2f..0e60c17a7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-pt-rBR/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html b/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html
index 655e98758..9a8e5a413 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ru/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (патчи криптографии)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Разработчики APG 1.x</h2>
<ul>
-<li>'Thialfihar' (главный разработчик)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QR коды, подписание и загрузка ключей)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Компоненты</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Библиотека Android AppMsg</a> (Apache License v2)</li>
-<li>Иконки <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Иконки <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html
index 2a324202f..447c04f17 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ru/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>удален не требующийся экспорт публичного ключа при экспорте секретного ключа (спасибо, Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html b/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html
index 9b2b99e96..4188f6d5f 100644
--- a/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-ru/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Приступая</h2>
-<p>Для начала вам понадобится своя пара ключей. Воспользуйтесь меню в разделе "Мои ключи", что бы создать новую, или добавьте ранее созданную пару в разделе "Импорт ключей". После этого вы сможете скачать ключи ваших друзей или обменяться ключами посредством QR кодов или NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>Рекомендуется установить <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> для удобного выбора файлов и <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> для распознавания QR кодов. Перейдите по ссылкам на соответствующие страницы Google Play или F-Droid для дальнейшей установки.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html
index 863aeee58..ae7e16aae 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (crypto patches)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Developers APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Lead developer)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QRCode, sign key, upload key)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Libraries</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html
index abf660ba8..1136deba6 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html
index 3a6443a2f..0e60c17a7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-sl-rSI/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html b/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html
index eb262b242..7d2c24f9c 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/help_about.html
@@ -11,13 +11,19 @@
<li>Ash Hughes (kripto yamaları)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (Arayüz)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Geliştiriciler APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Baş geliştirici)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QR Kodu, anahtar imzalama, anahtar yükleme)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
<h2>Kütüphaneler</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>İkonlar <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>İkonlar <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html
index abf660ba8..1136deba6 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html b/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html
index 3a6443a2f..0e60c17a7 100644
--- a/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-tr/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html b/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html
index c8a5a82c5..b839b50e1 100644
--- a/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-uk/help_about.html
@@ -11,13 +11,19 @@
<li>Аш Гюдж (латки шифрування)</li>
<li>Браян С. Барнс</li>
<li>Бахтіяр 'kalkin' Ґадімов (інтерфейс)</li>
-
+<li>Даніель Гаман</li>
+<li>Даніель Габ</li>
+<li>Ґреґ Вітчак</li>
+<li>Міроджін Бакші</li>
+<li>Nikhil Peter Raj</li>
+<li>Пауль Сарбіновський</li>
+<li>Sreeram Boyapati</li>
+<li>Вінсент Брейтмозер</li>
</ul>
<h2>Розробники APG 1.x</h2>
<ul>
-<li>'Thialfihar' (основний розробник)</li>
+<li>Thialfihar (основний розробник)</li>
<li>'Senecaso' (штрих-код, підпис і завантаження ключів)</li>
-<li>Олівер Ранж</li>
<li>Маркус Дойтс</li>
</ul>
<h2>Бібліотеки</h2>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (ліцензія Apache в.2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Бібліотека Android AppMsg Library</a> (Ліцензія Apache в. 2)</li>
-<li>Піктограми із <a href="http://rrze-icon-set.berlios.de/">набору піктограм RRZE</a> (ліцензія Creative Commons - Із зазначенням авторства - Розповсюдження на тих самих умовах - версія 3.0)</li>
-<li>Піктограми із <a href="http://tango.freedesktop.org/">набору піктограм Tango</a> (відкритий домен)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html
index 0b67fa3a9..826638e75 100644
--- a/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-uk/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>видалений непотрібний експорт публічного ключа при експорті секретного ключа (завдяки Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html b/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html
index 3bfb40f8a..45a3edb6a 100644
--- a/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-uk/help_start.html
@@ -2,7 +2,7 @@
<head></head>
<body>
<h2>Приступаючи до роботи</h2>
-<p>Спершу вам потрібна персональна в'язка ключів. Створіть одну через меню параметрів у "Мої Ключі" або імпортуйте наявні в'язки ключів через "Імпорт ключів". Після цього ви зможете завантажувати ключі ваших друзів чи обміняти їх через штрих-коди або NFC.</p>
+<p>Спершу вам потрібна персональна в'язка ключів. Створіть одну через меню параметрів у "Контактах" або імпортуйте наявні в'язки ключів через "Імпорт ключів". Після цього ви зможете завантажувати ключі ваших друзів чи обміняти їх через штрих-коди або NFC.</p>
<p>Рекомендуємо вам встановити <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> для поліпшеного виділення файлів та <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> для сканування згенерованих штрих-кодів. Натискання посилань відкриє Google Play або F-Droid для встановлення.</p>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_about.html b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_about.html
new file mode 100644
index 000000000..ae7e16aae
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_about.html
@@ -0,0 +1,49 @@
+<html>
+<head></head>
+<body>
+<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
+<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
+<p>License: GPLv3+</p>
+
+<h2>Developers OpenKeychain</h2>
+<ul>
+<li>Dominik Schürmann (Lead developer)</li>
+<li>Ash Hughes (crypto patches)</li>
+<li>Brian C. Barnes</li>
+<li>Bahtiar 'kalkin' Gadimov (UI)</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
+</ul>
+<h2>Developers APG 1.x</h2>
+<ul>
+<li>Thialfihar (Lead developer)</li>
+<li>'Senecaso' (QRCode, sign key, upload key)</li>
+<li>Markus Doits</li>
+</ul>
+<h2>Libraries</h2>
+<ul>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
+<li>
+<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li>
+<li>
+<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
+<li>
+<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
+<li>
+<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
+<li>
+<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_changelog.html
new file mode 100644
index 000000000..1136deba6
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_changelog.html
@@ -0,0 +1,129 @@
+<html>
+<head></head>
+<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
+<h2>2.3</h2>
+<ul>
+<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
+<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
+<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
+<li>querying keyservers directly from the import screen</li>
+<li>fix layout and dialog style on Android 2.2-3.0</li>
+<li>fix crash on keys with empty user ids</li>
+<li>fix crash and empty lists when coming back from signing screen</li>
+<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
+<li>fix upload of key from signing screen</li>
+</ul>
+<h2>2.2</h2>
+<ul>
+<li>new design with navigation drawer</li>
+<li>new public key list design</li>
+<li>new public key view</li>
+<li>bug fixes for importing of keys</li>
+<li>key cross-certification (thanks to Ash Hughes)</li>
+<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
+<li>first version with new languages (thanks to the contributors on Transifex)</li>
+<li>sharing of keys via QR Codes fixed and improved</li>
+<li>package signature verification for API</li>
+</ul>
+<h2>2.1.1</h2>
+<ul>
+<li>API Updates, preparation for K-9 Mail integration</li>
+</ul>
+<h2>2.1</h2>
+<ul>
+<li>lots of bug fixes</li>
+<li>new API for developers</li>
+<li>PRNG bug fix by Google</li>
+</ul>
+<h2>2.0</h2>
+<ul>
+<li>complete redesign</li>
+<li>share public keys via qr codes, nfc beam</li>
+<li>sign keys</li>
+<li>upload keys to server</li>
+<li>fixes import issues</li>
+<li>new AIDL API</li>
+</ul>
+<h2>1.0.8</h2>
+<ul>
+<li>basic keyserver support</li>
+<li>app2sd</li>
+<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
+<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
+<li>bugfixes</li>
+<li>optimizations</li>
+</ul>
+<h2>1.0.7</h2>
+<ul>
+<li>fixed problem with signature verification of texts with trailing newline</li>
+<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li>
+</ul>
+<h2>1.0.6</h2>
+<ul>
+<li>account adding crash on Froyo fixed</li>
+<li>secure file deletion</li>
+<li>option to delete key file after import</li>
+<li>stream encryption/decryption (gallery, etc.)</li>
+<li>new options (language, force v3 signatures)</li>
+<li>interface changes</li>
+<li>bugfixes</li>
+</ul>
+<h2>1.0.5</h2>
+<ul>
+<li>German and Italian translation</li>
+<li>much smaller package, due to reduced BC sources</li>
+<li>new preferences GUI</li>
+<li>layout adjustment for localization</li>
+<li>signature bugfix</li>
+</ul>
+<h2>1.0.4</h2>
+<ul>
+<li>fixed another crash caused by some SDK bug with query builder</li>
+</ul>
+<h2>1.0.3</h2>
+<ul>
+<li>fixed crashes during encryption/signing and possibly key export</li>
+</ul>
+<h2>1.0.2</h2>
+<ul>
+<li>filterable key lists</li>
+<li>smarter pre-selection of encryption keys</li>
+<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
+<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
+</ul>
+<h2>1.0.1</h2>
+<ul>
+<li>GMail account listing was broken in 1.0.0, fixed again</li>
+</ul>
+<h2>1.0.0</h2>
+<ul>
+<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
+<li>support of more file managers (including ASTRO)</li>
+<li>Slovenian translation</li>
+<li>new database, much faster, less memory usage</li>
+<li>defined Intents and content provider for other apps</li>
+<li>bugfixes</li>
+</ul>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_nfc_beam.html
new file mode 100644
index 000000000..88492731c
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_nfc_beam.html
@@ -0,0 +1,12 @@
+<html>
+<head></head>
+<body>
+<h2>How to receive keys</h2>
+<ol>
+<li>Go to your partners contacts and open the contact you want to share.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
+<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the your device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_start.html b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_start.html
new file mode 100644
index 000000000..0e60c17a7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/help_start.html
@@ -0,0 +1,19 @@
+<html>
+<head></head>
+<body>
+<h2>Getting started</h2>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+
+<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
+
+<h2>I found a bug in OpenKeychain!</h2>
+<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
+
+<h2>Contribute</h2>
+<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
+
+<h2>Translations</h2>
+<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh-rTW/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/nfc_beam_share.html
new file mode 100644
index 000000000..083e055c7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw-zh-rTW/nfc_beam_share.html
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<ol>
+<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
+<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
+<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
+<li>Tap the card and the content will then load on the other person’s device.</li>
+</ol>
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html
index 863aeee58..813676ea2 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_about.html
@@ -3,24 +3,30 @@
<body>
<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
-<p>License: GPLv3+</p>
+<p>授權:GPLv3+</p>
<h2>Developers OpenKeychain</h2>
<ul>
<li>Dominik Schürmann (Lead developer)</li>
<li>Ash Hughes (crypto patches)</li>
<li>Brian C. Barnes</li>
-<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Bahtiar 'kalkin' Gadimov (介面)</li>
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
<h2>Developers APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Lead developer)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QRCode, sign key, upload key)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
-<h2>Libraries</h2>
+<h2>函式庫</h2>
<ul>
<li>
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
@@ -38,8 +44,6 @@
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html
index abf660ba8..1136deba6 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_changelog.html
@@ -1,6 +1,27 @@
<html>
<head></head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html
index 88492731c..7a90a794b 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_nfc_beam.html
@@ -1,12 +1,12 @@
<html>
<head></head>
<body>
-<h2>How to receive keys</h2>
+<h2>如何接收金要</h2>
<ol>
-<li>Go to your partners contacts and open the contact you want to share.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li>
-<li>After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
-<li>Tap the card and the content will then load on the your device.</li>
+<li>前往你夥伴裝置上的聯絡人清單,並點選你要分享的聯絡人。</li>
+<li>將兩部裝置背對背貼近(幾乎接觸),你會感覺到一股震動。</li>
+<li>震動之後你會看見你夥伴的畫面變成卡片狀,並且背景帶有如 Star Trek 般的特效。</li>
+<li>輕觸卡片,內容隨即顯示在你的裝置上。</li>
</ol>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html b/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html
index 3a6443a2f..22ac99882 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/help_start.html
@@ -1,18 +1,18 @@
<html>
<head></head>
<body>
-<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<h2>快速上手</h2>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
-<h2>I found a bug in OpenKeychain!</h2>
-<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
+<h2>我在OpenKeychain發現問題!</h2>
+<p>請利用 <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">OpenKeychain 項目回報系統</a>回報問題。</p>
-<h2>Contribute</h2>
+<h2>發布</h2>
<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
-<h2>Translations</h2>
+<h2>翻譯</h2>
<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body>
diff --git a/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html
index 083e055c7..99ffe4c12 100644
--- a/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html
+++ b/OpenPGP-Keychain/src/main/res/raw-zh/nfc_beam_share.html
@@ -2,10 +2,10 @@
<head></head>
<body>
<ol>
-<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li>
-<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li>
-<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li>
-<li>Tap the card and the content will then load on the other person’s device.</li>
+<li>確定在 "設定" &gt; "更多內容…" &gt; "NFC" 裡面已經開啟 NFC 和 Android Beam。</li>
+<li>將兩部裝置背對背貼近(幾乎接觸),你會感覺到一股震動。</li>
+<li>震動之後你會看見你夥伴的畫面變成卡片狀,並且背景帶有如 Star Trek 般的特效。</li>
+<li>輕觸卡片,內容隨即顯示在你的裝置上。</li>
</ol>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_about.html b/OpenPGP-Keychain/src/main/res/raw/help_about.html
index 51e3f1325..847168446 100644
--- a/OpenPGP-Keychain/src/main/res/raw/help_about.html
+++ b/OpenPGP-Keychain/src/main/res/raw/help_about.html
@@ -15,13 +15,20 @@ And don't add newlines before or after p tags because of transifex -->
<li>Ash Hughes (crypto patches)</li>
<li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
-
+<li>Daniel Hammann</li>
+<li>Daniel Haß</li>
+<li>Greg Witczak</li>
+<li>Miroojin Bakshi</li>
+<li>Nikhil Peter Raj</li>
+<li>Paul Sarbinowski</li>
+<li>Sreeram Boyapati</li>
+<li>Vincent Breitmoser</li>
</ul>
+
<h2>Developers APG 1.x</h2>
<ul>
-<li>'Thialfihar' (Lead developer)</li>
+<li>Thialfihar (Lead developer)</li>
<li>'Senecaso' (QRCode, sign key, upload key)</li>
-<li>Oliver Runge</li>
<li>Markus Doits</li>
</ul>
@@ -35,8 +42,6 @@ And don't add newlines before or after p tags because of transifex -->
<li><a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li><a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li><a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
-<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
-<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul>
</body>
</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw/help_changelog.html
index 17ad853de..595878fe7 100644
--- a/OpenPGP-Keychain/src/main/res/raw/help_changelog.html
+++ b/OpenPGP-Keychain/src/main/res/raw/help_changelog.html
@@ -5,6 +5,29 @@ And don't add newlines before or after p tags because of transifex -->
<head>
</head>
<body>
+<h2>2.4</h2>
+<p>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):
+Daniel Hammann, Daniel Haß, Greg Witczak, Miroojin Bakshi, Nikhil Peter Raj, Paul Sarbinowski, Sreeram Boyapati, Vincent Breitmoser.</p>
+<ul>
+<li>new unified key list</li>
+<li>colorized key fingerprint</li>
+<li>support for keyserver ports</li>
+<li>deactivate possibility to generate weak keys</li>
+<li>much more internal work on the API</li>
+<li>certify user ids</li>
+<li>keyserver query based on machine-readable output</li>
+<li>lock navigation drawer on tablets</li>
+<li>suggestions for emails on creation of keys</li>
+<li>search in public key lists</li>
+<li>and much more improvements and fixes…</li>
+</ul>
+
+<h2>2.3.1</h2>
+<ul>
+<li>hotfix for crash when upgrading from old versions</li>
+</ul>
+
<h2>2.3</h2>
<ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_faq.html b/OpenPGP-Keychain/src/main/res/raw/help_faq.html
new file mode 100644
index 000000000..bfd43eafd
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/raw/help_faq.html
@@ -0,0 +1,13 @@
+<!-- Maintain structure with headings with h2 tags and content with p tags.
+This makes it easy to translate the values with transifex!
+And don't add newlines before or after p tags because of transifex -->
+<html>
+<head>
+</head>
+<body>
+<h2>How can I specify connection port for Keyserver?</h2>
+<p>Add a new Keyserver (or modify existing one) by going to Preferences -> General -> Keyservers. Enter the port number after the Keyserver address and preceded it by a colon. For example, "p80.pool.sks-keyservers.net:80" (without quotation marks) means that server "p80.pool.sks-keyservers.net" is working on a port 80.</p>
+<p>Default connection port is 11371 and it doesn't need to be specified.</p>
+
+</body>
+</html>
diff --git a/OpenPGP-Keychain/src/main/res/raw/help_start.html b/OpenPGP-Keychain/src/main/res/raw/help_start.html
index 7afac0f08..56c02b1fd 100644
--- a/OpenPGP-Keychain/src/main/res/raw/help_start.html
+++ b/OpenPGP-Keychain/src/main/res/raw/help_start.html
@@ -6,7 +6,7 @@ And don't add newlines before or after p tags because of transifex -->
</head>
<body>
<h2>Getting started</h2>
-<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
+<p>First you need a personal key pair. Create one via the option menus in "Contacts" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
diff --git a/OpenPGP-Keychain/src/main/res/values-cs-rCZ/strings.xml b/OpenPGP-Keychain/src/main/res/values-cs-rCZ/strings.xml
new file mode 100644
index 000000000..9207318d3
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-cs-rCZ/strings.xml
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <string name="title_manage_public_keys">Kontakty</string>
+ <string name="title_manage_secret_keys">Tajné klíče</string>
+ <string name="title_select_recipients">Zvolit veřejný klíč</string>
+ <string name="title_select_secret_key">Zvolit tajný klíč</string>
+ <string name="title_encrypt">Zašifrovat</string>
+ <string name="title_decrypt">Dešifrovat</string>
+ <string name="title_authentication">Heslo</string>
+ <string name="title_create_key">Vytvořit klíč</string>
+ <string name="title_edit_key">Upravit klíč</string>
+ <string name="title_preferences">Nastavení</string>
+ <string name="title_api_registered_apps">Registrované aplikace</string>
+ <string name="title_key_server_preference">Nastavení serveru s klíči</string>
+ <string name="title_set_passphrase">Zadat heslo</string>
+ <string name="title_send_email">Poslat zprávu...</string>
+ <string name="title_import_keys">Importovat klíče</string>
+ <string name="title_export_key">Exportovat klíč</string>
+ <string name="title_export_keys">Exportovat klíče</string>
+ <string name="title_key_not_found">Klíč nenalezen</string>
+ <string name="title_send_key">Nahrát na server s klíči</string>
+ <string name="title_help">Nápověda</string>
+ <!--section-->
+ <string name="section_keys">Klíče</string>
+ <!--button-->
+ <string name="btn_sign">Podepsat</string>
+ <!--menu-->
+ <!--label-->
+ <string name="unknown_status"></string>
+ <!--choice-->
+ <!--sentences-->
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <!--progress dialogs, usually ending in '…'-->
+ <!--action strings-->
+ <!--key bit length selections-->
+ <!--compression-->
+ <!--Help-->
+ <!--Import-->
+ <!--Intent labels-->
+ <!--Remote API-->
+ <!--Share-->
+ <!--Key list-->
+ <!--Key view-->
+ <!--Navigation Drawer-->
+ <!--hints-->
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-de/strings.xml b/OpenPGP-Keychain/src/main/res/values-de/strings.xml
index ea1e550e3..493b81314 100644
--- a/OpenPGP-Keychain/src/main/res/values-de/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-de/strings.xml
@@ -13,9 +13,10 @@
<string name="title_preferences">Einstellungen</string>
<string name="title_api_registered_apps">Registrierte Anwendungen</string>
<string name="title_key_server_preference">Schlüsselserver</string>
- <string name="title_change_passphrase">Passwort ändern</string>
+ <string name="title_change_passphrase">Passphrase ändern</string>
<string name="title_set_passphrase">Passwort setzen</string>
- <string name="title_send_email">E-Mail senden…</string>
+ <string name="title_send_email">E-Mail senden...</string>
+ <string name="title_send_file">Datei senden</string>
<string name="title_encrypt_to_file">In eine Datei verschlüsseln</string>
<string name="title_decrypt_to_file">In eine Datei entschlüsseln</string>
<string name="title_import_keys">Schlüssel importieren</string>
@@ -63,6 +64,8 @@
<string name="btn_clipboard">Zwischenablage</string>
<string name="btn_share">Teilen mit…</string>
<string name="btn_lookup_key">Schlüssel nachschlagen</string>
+ <string name="btn_encryption_advanced_settings_show">Erweiterte Einstellungen anzeigen</string>
+ <string name="btn_encryption_advanced_settings_hide">Erweiterte Einstellungen verbergen</string>
<!--menu-->
<string name="menu_preferences">Einstellungen</string>
<string name="menu_help">Hilfe</string>
@@ -71,15 +74,17 @@
<string name="menu_import">Importieren</string>
<string name="menu_import_from_nfc">NFC</string>
<string name="menu_export_keys">Alle Schlüssel exportieren</string>
+ <string name="menu_export_secret_keys">Alle geheimen Schlüssel exportieren</string>
<string name="menu_export_key">In Datei exportieren</string>
<string name="menu_delete_key">Schlüssel löschen</string>
<string name="menu_create_key">Schlüssel erstellen</string>
<string name="menu_create_key_expert">Schlüssel erstellen (Experte)</string>
<string name="menu_search">Suchen</string>
- <string name="menu_key_server">Schlüsselserver</string>
+ <string name="menu_import_from_key_server">Schlüsselserver</string>
+ <string name="menu_key_server">Schlüsselserver…</string>
<string name="menu_update_key">Von einem Schlüsselserver aktualisieren</string>
<string name="menu_export_key_to_server">Auf Schlüsselserver hochladen</string>
- <string name="menu_share">Teilen</string>
+ <string name="menu_share">Teilen…</string>
<string name="menu_share_title_fingerprint">Teile Fingerabdruck…</string>
<string name="menu_share_title">Teile gesamten Schlüssel…</string>
<string name="menu_share_default_fingerprint">mit…</string>
@@ -92,6 +97,7 @@
<string name="menu_beam_preferences">Beam-Einstellungen</string>
<string name="menu_key_edit_cancel">Abbrechen</string>
<string name="menu_encrypt_to">Verschlüsseln nach…</string>
+ <string name="menu_select_all">Alles auswählen</string>
<!--label-->
<string name="label_sign">Signieren</string>
<string name="label_message">Nachricht</string>
@@ -104,6 +110,7 @@
<string name="label_select_public_keys">Empfänger</string>
<string name="label_delete_after_encryption">Nach Verschlüsselung löschen</string>
<string name="label_delete_after_decryption">Nach Entschlüsselung löschen</string>
+ <string name="label_share_after_encryption">Nach dem Verschlüsseln teilen</string>
<string name="label_encryption_algorithm">Verschlüsselungsalgorithmus</string>
<string name="label_hash_algorithm">Hash-Algorithmus</string>
<string name="label_asymmetric">Öffentlicher Schlüssel</string>
@@ -122,9 +129,12 @@
<string name="label_name">Name</string>
<string name="label_comment">Kommentar</string>
<string name="label_email">E-Mail</string>
+ <string name="label_sign_user_id">Benutzer ID unterschreiben</string>
+ <string name="label_sign_email">Email unterschreiben</string>
<string name="label_send_key">Schlüssel nach Beglaubigung auf ausgewählten Schlüsselserver hochladen</string>
<string name="label_fingerprint">Fingerabdruck</string>
<string name="select_keys_button_default">Auswählen</string>
+ <string name="expiry_date_dialog_title">Ablaufdatum festsetzen</string>
<plurals name="select_keys_button">
<item quantity="one">%d ausgewählt</item>
<item quantity="other">%d ausgewählt</item>
@@ -132,11 +142,17 @@
<string name="user_id_no_name">&lt;kein Name&gt;</string>
<string name="none">&lt;keine&gt;</string>
<string name="no_key">&lt;kein Schlüssel&gt;</string>
+ <string name="no_email">&lt;Keine E-Mail&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">kann verschlüsseln</string>
<string name="can_sign">kann signieren</string>
<string name="expired">abgelaufen</string>
<string name="revoked">zurückgezogen</string>
+ <string name="user_id">Benutzer ID</string>
+ <plurals name="n_contacts">
+ <item quantity="one">1 Kontakt</item>
+ <item quantity="other">%d Kontakte</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="one">%d Schlüsselserver</item>
<item quantity="other">%d Schlüsselserver</item>
@@ -163,7 +179,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">Öffnen…</string>
+ <string name="filemanager_title_open">Öffnen...</string>
<string name="warning">Warnung</string>
<string name="error">Fehler</string>
<string name="error_message">Fehler: %s</string>
@@ -192,6 +208,7 @@
<string name="key_deletion_confirmation">Soll der Schlüssel \'%s\' wirklich gelöscht werden?\nDies kann nicht rückgängig gemacht werden! </string>
<string name="key_deletion_confirmation_multi">Möchtest du wirklich alle ausgewählten Schlüssel löschen?\nDies kann nicht rückgängig gemacht werden!</string>
<string name="secret_key_deletion_confirmation">Soll der PRIVATE Schlüssel \'%s\' wirklich gelöscht werden?\nDies kann nicht rückgängig gemacht werden!</string>
+ <string name="also_export_secret_keys">Private Schlüssel auch exportieren</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">%d Schlüssel erfolgreich hinzugefügt</item>
<item quantity="other">%d Schlüssel erfolgreich hinzugefügt</item>
@@ -213,6 +230,7 @@
<string name="keys_exported">%d Schlüssel erfolgreich exportiert.</string>
<string name="no_keys_exported">Keine Schlüssel exportiert.</string>
<string name="key_creation_el_gamal_info">Beachte: nur Unterschlüssel unterstützen ElGamal. Für ElGamal wird die am nächsten liegende Schlüssellänge von 1536, 2048, 3072, 4096 oder 8192 verwendet.</string>
+ <string name="key_creation_weak_rsa_info">Beachte: RSA-Schlüssel mit einer Schlüssellänge von 1024-Bits oder weniger werden als unsicher angesehen und können daher nicht für neue Schlüssel erstellt werden.</string>
<string name="key_not_found">Schlüssel %08X konnte nicht gefunden werden.</string>
<plurals name="keys_found">
<item quantity="one">%d Schlüssel gefunden.</item>
@@ -244,6 +262,7 @@
<string name="error_master_key_must_not_be_el_gamal">Der Hauptschlüssel kann kein ElGamal Schlüssel sein</string>
<string name="error_unknown_algorithm_choice">Unbekannte Auswahl für Algorithmus</string>
<string name="error_user_id_needs_a_name">ein Name muss angegeben werden</string>
+ <string name="error_user_id_no_email">keine E-Mail gefunden</string>
<string name="error_user_id_needs_an_email_address">eine E-Mail-Adresse muss angegeben werden</string>
<string name="error_key_needs_a_user_id">Mindestens eine Benutzer-ID wird benötigt</string>
<string name="error_main_user_id_must_not_be_empty">Hauptbenutzer-ID darf nicht leer sein</string>
@@ -266,17 +285,25 @@
<string name="error_expiry_must_come_after_creation">Ablaufdatum muss später sein als das Erstellungsdatum</string>
<string name="error_can_not_delete_contact">Sie können diesen Kontakt nicht löschen, denn es ist ihr eigener.</string>
<string name="error_can_not_delete_contacts">Sie können folgende Kontakte nicht löschen, denn sie gehören Ihnen selbst:\n%s</string>
+ <string name="error_keyserver_insufficient_query">Unzureichende Serveranfrage</string>
<string name="error_keyserver_query">Keyserveranfrage fehlgeschlagen</string>
+ <string name="error_keyserver_too_many_responses">Zu viele Antworten</string>
+ <string name="error_import_file_no_content">Datei ist leer</string>
+ <string name="error_generic_report_bug">Ein allgemeiner Fehler trat auf, bitte schreiben Sie einen neuen Bugreport für OpenKeychain.</string>
<plurals name="error_can_not_delete_info">
<item quantity="one">Bitte lösche ihn unter \'Meine Schlüssel\'!</item>
<item quantity="other">Bitte lösche sie unter \'Meine Schlüssel\'!</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="one">Ein Teil der geladenen Datei ist ein gültiges OpenPGP Objekt aber kein OpenPGP Schlüssel</item>
+ <item quantity="other">Teile der geladenen Dateien sind gültige OpenPGP Objekte aber keine OpenPGP Schlüssel</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">fertig.</string>
+ <string name="progress_done">Erledigt</string>
+ <string name="progress_cancel">Abbrechen</string>
<string name="progress_saving">speichern…</string>
<string name="progress_importing">importieren…</string>
<string name="progress_exporting">exportieren…</string>
- <string name="progress_generating">erstelle Schlüssel, dies kann bis zu 3 Minuten dauern…</string>
<string name="progress_building_key">erstelle Schlüssel…</string>
<string name="progress_preparing_master_key">Hauptschlüssel wird vorbereitet…</string>
<string name="progress_certifying_master_key">Hauptschlüssel wird beglaubigt…</string>
@@ -287,6 +314,10 @@
<item quantity="one">Schlüssel wird exportiert…</item>
<item quantity="other">Schlüssel werden exportiert…</item>
</plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">erstelle Schlüssel, das kann bis zu 3 Minuten dauern…</item>
+ <item quantity="other">erstelle Schlüssel, das kann bis zu 3 Minuten dauern…</item>
+ </plurals>
<string name="progress_extracting_signature_key">extrahiere Signaturschlüssel…</string>
<string name="progress_extracting_key">extrahiere Schlüssel…</string>
<string name="progress_preparing_streams">Datenstrom wird vorbereitet…</string>
@@ -317,6 +348,7 @@
<string name="compression_very_slow">sehr langsam</string>
<!--Help-->
<string name="help_tab_start">Start</string>
+ <string name="help_tab_faq">FAQ</string>
<string name="help_tab_nfc_beam">NFC-Beam</string>
<string name="help_tab_changelog">Changelog</string>
<string name="help_tab_about">Über</string>
@@ -338,6 +370,10 @@
<string name="import_nfc_help_button">Hilfe</string>
<string name="import_clipboard_button">Füge den Schlüssel aus der Zwischenablage ein</string>
<!--Intent labels-->
+ <string name="intent_decrypt_file">Datei mit OpenKeychain entschlüsseln</string>
+ <string name="intent_import_key">Schlüssel mit OpenKeychain importieren</string>
+ <string name="intent_send_encrypt">Mit OpenKeychain verschlüsseln</string>
+ <string name="intent_send_decrypt">Mit OpenKeychain entschlüsseln</string>
<!--Remote API-->
<string name="api_no_apps">Keine registrierten Anwendungen vorhanden!\n\nAnwendungen von Dritten können Zugriff auf OpenKeychain erbitten. Nachdem Zugriff gewährt wurde, werden diese hier aufgelistet.</string>
<string name="api_settings_show_advanced">Erweiterte Einstellungen anzeigen</string>
@@ -374,6 +410,7 @@
<string name="key_list_empty_button_create">deinen eigenen Schlüssel erstellst</string>
<string name="key_list_empty_button_import">existierende Schlüssel importierst.</string>
<!--Key view-->
+ <string name="key_view_action_edit">Diesen Schlüssel bearbeiten</string>
<string name="key_view_action_encrypt">Für diesen Kontakt verschlüsseln</string>
<string name="key_view_action_certify">Schlüssel dieses Kontakts beglaubigen</string>
<string name="key_view_tab_main">Info</string>
@@ -387,4 +424,12 @@
<string name="nav_apps">Registrierte Anwendungen</string>
<string name="drawer_open">Menu öffnen</string>
<string name="drawer_close">Menu schließen</string>
+ <string name="edit">Bearbeiten</string>
+ <string name="my_keys">Meine Schlüssel</string>
+ <string name="label_secret_key">Geheime Schlüssel</string>
+ <string name="secret_key_yes">verfügbar</string>
+ <string name="secret_key_no">nicht verfügbar</string>
+ <string name="section_uids_to_sign">Benutzer-IDs, die beglaubigt werden sollen</string>
+ <string name="progress_re_adding_certs">Wiederhinzufügen der Zertifikate</string>
+ <!--hints-->
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-el/strings.xml b/OpenPGP-Keychain/src/main/res/values-el/strings.xml
new file mode 100644
index 000000000..094dfe28a
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-el/strings.xml
@@ -0,0 +1,54 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <string name="title_select_recipients">Επιλογή Δημόσιου Κλειδιού</string>
+ <string name="title_select_secret_key">Επιλογή Ιδιωτικού Κλειδιού</string>
+ <string name="title_authentication">Κωδικός</string>
+ <string name="title_create_key">Δημιουργία Κλειδιού</string>
+ <string name="title_edit_key">Επεξεργασία Κλειδιού</string>
+ <string name="title_preferences">Επιλογές</string>
+ <!--section-->
+ <!--button-->
+ <string name="btn_sign">Υπόγραψε</string>
+ <string name="btn_save">Αποθήκευση</string>
+ <string name="btn_do_not_save">Ακύρωση</string>
+ <string name="btn_delete">Διαγραφή</string>
+ <string name="btn_no_date">Κανένα</string>
+ <string name="btn_okay">ΟΚ</string>
+ <string name="btn_change_passphrase">Αλλαγή κωδικού</string>
+ <string name="btn_set_passphrase">Επέλεξε Κωδικό</string>
+ <!--menu-->
+ <string name="menu_delete_key">Διαγραφής κλειδιού</string>
+ <string name="menu_create_key">Δημιουργίας κλειδιού</string>
+ <!--label-->
+ <string name="label_sign">Υπόγραψε</string>
+ <string name="label_message">Μήνυμα</string>
+ <string name="label_file">Αρχείο</string>
+ <string name="label_passphrase">Κωδικός</string>
+ <string name="label_passphrase_again">Ξανά</string>
+ <string name="label_algorithm">Αλγόριθμος</string>
+ <string name="label_encryption_algorithm">Αλγόριθμος κρυπτογράφησης</string>
+ <string name="label_asymmetric">Δημόσιο κλειδί</string>
+ <string name="label_symmetric">Κωδικός</string>
+ <string name="label_key_size">Μέγεθος κλειδιού</string>
+ <string name="label_email">Ηλεκτρονικό ταχυδρομίο</string>
+ <string name="unknown_status"></string>
+ <!--choice-->
+ <!--sentences-->
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <!--progress dialogs, usually ending in '…'-->
+ <!--action strings-->
+ <!--key bit length selections-->
+ <!--compression-->
+ <!--Help-->
+ <!--Import-->
+ <!--Intent labels-->
+ <!--Remote API-->
+ <!--Share-->
+ <!--Key list-->
+ <!--Key view-->
+ <!--Navigation Drawer-->
+ <!--hints-->
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml b/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml
index d1f0bd75b..ce365b776 100644
--- a/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml
@@ -10,9 +10,8 @@
<string name="title_edit_key">Editar clave</string>
<string name="title_preferences">Preferencias</string>
<string name="title_api_registered_apps">Aplicaciones registradas</string>
- <string name="title_change_passphrase">Cambiar contraseña</string>
<string name="title_set_passphrase">Establecer contraseña</string>
- <string name="title_send_email">Enviar correo electrónico…</string>
+ <string name="title_send_email">Enviar correo electrónico...</string>
<string name="title_encrypt_to_file">Cifrar a archivo</string>
<string name="title_decrypt_to_file">Descifrar a archivo</string>
<string name="title_import_keys">Importar claves</string>
@@ -98,4 +97,5 @@
<!--Key list-->
<!--Key view-->
<!--Navigation Drawer-->
+ <!--hints-->
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-es/strings.xml b/OpenPGP-Keychain/src/main/res/values-es/strings.xml
index de680337f..d7436e02d 100644
--- a/OpenPGP-Keychain/src/main/res/values-es/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-es/strings.xml
@@ -13,9 +13,10 @@
<string name="title_preferences"> Preferencias</string>
<string name="title_api_registered_apps">Aplicaciones registradas</string>
<string name="title_key_server_preference">Prioridad del servidor de claves</string>
- <string name="title_change_passphrase">Cambiar la frase de contraseña</string>
+ <string name="title_change_passphrase">Cambiar frase de contraseña</string>
<string name="title_set_passphrase">Establecer frase de contraseña</string>
- <string name="title_send_email">Enviar email…</string>
+ <string name="title_send_email">Enviar email...</string>
+ <string name="title_send_file">Enviar archivo...</string>
<string name="title_encrypt_to_file">Cifrar hacia archivo</string>
<string name="title_decrypt_to_file">Descifrar hacia archivo</string>
<string name="title_import_keys">Importar claves</string>
@@ -61,8 +62,10 @@
<string name="btn_next">Siguiente</string>
<string name="btn_back">Volver</string>
<string name="btn_clipboard">Portapapeles</string>
- <string name="btn_share">Compartir con…</string>
+ <string name="btn_share">Compartir con...</string>
<string name="btn_lookup_key">Buscar clave</string>
+ <string name="btn_encryption_advanced_settings_show">Mostrar ajustes avanzados</string>
+ <string name="btn_encryption_advanced_settings_hide">Ocultar ajustes avanzados</string>
<!--menu-->
<string name="menu_preferences">Ajustes</string>
<string name="menu_help">Ayuda</string>
@@ -71,19 +74,21 @@
<string name="menu_import">Importar</string>
<string name="menu_import_from_nfc">Importar desde NFC</string>
<string name="menu_export_keys">Exportar todas las claves</string>
+ <string name="menu_export_secret_keys">Exportar todas las claves secretas</string>
<string name="menu_export_key">Exportar hacia archivo</string>
<string name="menu_delete_key">Borrar clave</string>
<string name="menu_create_key">Crear clave</string>
<string name="menu_create_key_expert">Crear clave (experto)</string>
<string name="menu_search">Buscar</string>
- <string name="menu_key_server">Importar desde servidor de claves</string>
+ <string name="menu_import_from_key_server">Servidor de claves...</string>
+ <string name="menu_key_server">Servidor de claves...</string>
<string name="menu_update_key">Actualizar desde servidor de claves</string>
<string name="menu_export_key_to_server">Cargar al servidor de claves</string>
- <string name="menu_share">Compartir</string>
- <string name="menu_share_title_fingerprint">Compartir la huella digital…</string>
- <string name="menu_share_title">Compartir la clave completa…</string>
- <string name="menu_share_default_fingerprint">con…</string>
- <string name="menu_share_default">con…</string>
+ <string name="menu_share">Compartir...</string>
+ <string name="menu_share_title_fingerprint">Compartir la huella digital...</string>
+ <string name="menu_share_title">Compartir la clave completa...</string>
+ <string name="menu_share_default_fingerprint">con...</string>
+ <string name="menu_share_default">con...</string>
<string name="menu_share_qr_code">con código QR</string>
<string name="menu_share_qr_code_fingerprint">con código QR</string>
<string name="menu_share_nfc">con NFC</string>
@@ -91,7 +96,8 @@
<string name="menu_sign_key"> Clave de firma</string>
<string name="menu_beam_preferences">Ajustes de Beam</string>
<string name="menu_key_edit_cancel">Cancelar</string>
- <string name="menu_encrypt_to">Cifrar hacia…</string>
+ <string name="menu_encrypt_to">Cifrar hacia...</string>
+ <string name="menu_select_all">Seleccionar todo</string>
<!--label-->
<string name="label_sign">Firmar</string>
<string name="label_message">Mensaje</string>
@@ -104,6 +110,7 @@
<string name="label_select_public_keys">Destinatarios</string>
<string name="label_delete_after_encryption">Borrar después del cifrado</string>
<string name="label_delete_after_decryption">Borrar después del descifrado</string>
+ <string name="label_share_after_encryption">Compartir después del cifrado</string>
<string name="label_encryption_algorithm">Algoritmo de cifrado</string>
<string name="label_hash_algorithm">Algoritmo de Hash</string>
<string name="label_asymmetric">Clave pública</string>
@@ -122,9 +129,12 @@
<string name="label_name">Nombre</string>
<string name="label_comment">Comentario</string>
<string name="label_email">Email</string>
+ <string name="label_sign_user_id">Firmar Id de usuario</string>
+ <string name="label_sign_email">Firmar correo</string>
<string name="label_send_key">Cargar clave al servidor de claves seleccionado después de la certificación</string>
<string name="label_fingerprint">Huella digital</string>
<string name="select_keys_button_default">Seleccionar</string>
+ <string name="expiry_date_dialog_title">Establer la fecha de vencimiento</string>
<plurals name="select_keys_button">
<item quantity="one">%d seleccionado</item>
<item quantity="other">%d seleccionados</item>
@@ -132,11 +142,17 @@
<string name="user_id_no_name">&lt;sin nombre&gt;</string>
<string name="none">&lt;ninguna&gt;</string>
<string name="no_key">&lt;sin clave&gt;</string>
+ <string name="no_email">&lt;No hay un email&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">se puede cifrar</string>
<string name="can_sign">se puede firmar</string>
<string name="expired">caducado</string>
<string name="revoked">revocado</string>
+ <string name="user_id">ID de usuario</string>
+ <plurals name="n_contacts">
+ <item quantity="one">1 contacto</item>
+ <item quantity="other">%d contactos</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="one">%d servidor de claves</item>
<item quantity="other">%d servidores de claves</item>
@@ -163,7 +179,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">Abrir…</string>
+ <string name="filemanager_title_open">Abrir...</string>
<string name="warning">Advertencia</string>
<string name="error">Error</string>
<string name="error_message">Error: %s</string>
@@ -192,6 +208,9 @@
<string name="key_deletion_confirmation">¿Quieres realmente borrar la clave \'%s\'?\n¡No podrás deshacerlo!</string>
<string name="key_deletion_confirmation_multi">¿Quieres realmente borrar todas las claves seleccionadas?\n¡No podrás deshacerlo!</string>
<string name="secret_key_deletion_confirmation">¿Quieres realmente borrar la clave SECRETA \'%s\'?\n¡No podrás deshacerlo!</string>
+ <string name="public_key_deletetion_confirmation">¿Quieres realmente borrar la clave PÚBLICA \'%s\'?\n¡No podrás deshacerlo!</string>
+ <string name="secret_key_delete_text">¿Borrar claves secretas?</string>
+ <string name="also_export_secret_keys">¿Exportar también las claves secretas?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">%d clave añadida satisfactoriamente</item>
<item quantity="other">%d claves añadidas satisfactoriamente</item>
@@ -213,6 +232,7 @@
<string name="keys_exported">%d claves exportadas satisfactoriamente.</string>
<string name="no_keys_exported">No se han exportado claves.</string>
<string name="key_creation_el_gamal_info">Nota: solo las subclaves son compatibles con ElGamal, y para ElGamal debe usarse el tamaño de clave más próximo de 1536, 2048, 3072, 4096, o 8192.</string>
+ <string name="key_creation_weak_rsa_info">Nota: generar una clave RSA de longitud 1024-bit o menos está considerado inseguro y desactivado para generar nuevas claves.</string>
<string name="key_not_found">No se puede encontrar la clave %08X.</string>
<plurals name="keys_found">
<item quantity="one">Se ha encontrado %d clave.</item>
@@ -244,6 +264,7 @@
<string name="error_master_key_must_not_be_el_gamal">la clave maestra no puede ser una clave ElGamal</string>
<string name="error_unknown_algorithm_choice">elegido algoritmo desconocido</string>
<string name="error_user_id_needs_a_name">necesitas determinar un nombre</string>
+ <string name="error_user_id_no_email">no se ha encontrado un email</string>
<string name="error_user_id_needs_an_email_address">tienes que determinar una dirección de email</string>
<string name="error_key_needs_a_user_id">necesitas al menos una ID de usuario</string>
<string name="error_main_user_id_must_not_be_empty">la ID del usuario principal no puede estar vacía</string>
@@ -269,46 +290,56 @@
<string name="error_keyserver_insufficient_query">Consulta al servidor insuficiente</string>
<string name="error_keyserver_query">La consulta al servidor de claves ha fallado</string>
<string name="error_keyserver_too_many_responses">Demasiadas respuestas</string>
+ <string name="error_import_file_no_content">El archivo está vacio</string>
+ <string name="error_generic_report_bug">Ha ocurrido un error genérico, por favor, informa de este bug a OpenKeychain</string>
<plurals name="error_can_not_delete_info">
<item quantity="one">Por favor, bórralo desde la pantalla \'Mis claves\'!</item>
<item quantity="other">Por favor, bórralos desde la pantalla \'Mis claves\'!</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="one">parte del archivo cargado es un objeto OpenPGP válido pero no una clave OpenPGP</item>
+ <item quantity="other">partes del archivo cargado son objetos OpenPGP válidos pero no claves OpenPGP</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">hecho.</string>
- <string name="progress_saving">guardando…</string>
- <string name="progress_importing">importando…</string>
- <string name="progress_exporting">exportando…</string>
- <string name="progress_generating">generando la clave, esto puede tardar más de 3 minutos…</string>
- <string name="progress_building_key">construyendo la clave…</string>
- <string name="progress_preparing_master_key">preparando la clave maestra…</string>
- <string name="progress_certifying_master_key">certificando la clave maestra…</string>
- <string name="progress_building_master_key">construyendo el anillo maestro…</string>
- <string name="progress_adding_sub_keys">añadiendo las subclaves…</string>
- <string name="progress_saving_key_ring">guardando claves…</string>
+ <string name="progress_done">Hecho.</string>
+ <string name="progress_cancel">Cancelar</string>
+ <string name="progress_saving">guardando...</string>
+ <string name="progress_importing">importando...</string>
+ <string name="progress_exporting">exportando...</string>
+ <string name="progress_building_key">construyendo la clave...</string>
+ <string name="progress_preparing_master_key">preparando la clave maestra...</string>
+ <string name="progress_certifying_master_key">certificando la clave maestra...</string>
+ <string name="progress_building_master_key">construyendo el anillo maestro...</string>
+ <string name="progress_adding_sub_keys">añadiendo las subclaves...</string>
+ <string name="progress_saving_key_ring">guardando claves...</string>
<plurals name="progress_exporting_key">
- <item quantity="one">exportando clave…</item>
- <item quantity="other">exportando claves…</item>
+ <item quantity="one">exportando clave...</item>
+ <item quantity="other">exportando claves...</item>
+ </plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">generando clave, esto puede tardar más de 3 minutos...</item>
+ <item quantity="other">generando claves, esto puede tardar más de 3 minutos...</item>
</plurals>
- <string name="progress_extracting_signature_key">extrayendo la clave de firma…</string>
- <string name="progress_extracting_key">extrayendo la clave…</string>
- <string name="progress_preparing_streams">preparando las transmisiones…</string>
- <string name="progress_encrypting">cifrando los datos…</string>
- <string name="progress_decrypting">descifrando los datos…</string>
- <string name="progress_preparing_signature">preparando la firma…</string>
- <string name="progress_generating_signature">generando la firma…</string>
- <string name="progress_processing_signature">procesando la firma…</string>
- <string name="progress_verifying_signature">verificando la firma…</string>
- <string name="progress_signing">firmando…</string>
- <string name="progress_reading_data">leyendo los datos…</string>
- <string name="progress_finding_key">localizando la clave…</string>
- <string name="progress_decompressing_data">descomprimiendo los datos…</string>
- <string name="progress_verifying_integrity">verificando la integridad…</string>
+ <string name="progress_extracting_signature_key">extrayendo la clave de firma...</string>
+ <string name="progress_extracting_key">extrayendo la clave...</string>
+ <string name="progress_preparing_streams">preparando las transmisiones...</string>
+ <string name="progress_encrypting">cifrando los datos...</string>
+ <string name="progress_decrypting">descifrando los datos...</string>
+ <string name="progress_preparing_signature">preparando la firma...</string>
+ <string name="progress_generating_signature">generando la firma...</string>
+ <string name="progress_processing_signature">procesando la firma...</string>
+ <string name="progress_verifying_signature">verificando la firma...</string>
+ <string name="progress_signing">firmando...</string>
+ <string name="progress_reading_data">leyendo los datos...</string>
+ <string name="progress_finding_key">localizando la clave...</string>
+ <string name="progress_decompressing_data">descomprimiendo los datos...</string>
+ <string name="progress_verifying_integrity">verificando la integridad...</string>
<string name="progress_deleting_securely">borrando \'%s\' de forma segura…</string>
- <string name="progress_querying">consultando…</string>
+ <string name="progress_querying">consultando...</string>
<!--action strings-->
<string name="hint_public_keys">Buscar claves públicas</string>
<string name="hint_secret_keys">Buscar claves secretas</string>
- <string name="action_share_key_with">Compartir la clave con…</string>
+ <string name="action_share_key_with">Compartir la clave con...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_1024">1024</string>
@@ -319,6 +350,7 @@
<string name="compression_very_slow">muy lento</string>
<!--Help-->
<string name="help_tab_start">Comenzar</string>
+ <string name="help_tab_faq">FAQ</string>
<string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Registro de cambios</string>
<string name="help_tab_about">A cerca de</string>
@@ -346,6 +378,8 @@
<string name="intent_send_decrypt">Descifrar con OpenKeychain</string>
<!--Remote API-->
<string name="api_no_apps">¡No hay aplicaciones registradas!\n\nLas aplicaciones de terceros pueden pedir permiso de acceso a OpenKeychain. Después de obtener acceso, serán enumeradas aquí.</string>
+ <string name="api_settings_show_info">Mostrar información avanzada</string>
+ <string name="api_settings_hide_info">Ocultar información avanzada</string>
<string name="api_settings_show_advanced">Mostrar la configuración avanzada</string>
<string name="api_settings_hide_advanced">Ocultar la configuración avanzada</string>
<string name="api_settings_no_key">No se ha seleccionado ninguna clave</string>
@@ -355,6 +389,8 @@
<string name="api_settings_revoke">Revocar acceso</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_accounts">Cuentas</string>
+ <string name="api_settings_accounts_empty">No hay cuentas asociadas a esta aplicación.</string>
<string name="api_register_text">La aplicación mostrada solicita acceso a OpenKeychain.\n¿Permitir el acceso?\n\nAVISO: Si no sabes por qué aparece esta pantalla, ¡deniega el acceso! Puedes revocarlo después usando la pantalla \'Aplicaciones registradas\'.</string>
<string name="api_register_allow">Permitir el acceso</string>
<string name="api_register_disallow">Denegar el acceso</string>
@@ -374,12 +410,13 @@
<item quantity="one">1 clave seleccionada.</item>
<item quantity="other">%d claves seleccionadas.</item>
</plurals>
- <string name="key_list_empty_text1">Aún no hay claves disponibles…</string>
+ <string name="key_list_empty_text1">Aún no hay claves disponibles...</string>
<string name="key_list_empty_text2">Puedes empezar por</string>
<string name="key_list_empty_text3">o</string>
<string name="key_list_empty_button_create">crear tu propia clave</string>
<string name="key_list_empty_button_import">importar claves</string>
<!--Key view-->
+ <string name="key_view_action_edit">Editar esta clave</string>
<string name="key_view_action_encrypt">Cifrar hacia este contacto</string>
<string name="key_view_action_certify">Certificar la clave de este contacto</string>
<string name="key_view_tab_main">Información</string>
@@ -393,4 +430,13 @@
<string name="nav_apps">Aplicaciones registradas</string>
<string name="drawer_open">Abrir el Navigation Drawer</string>
<string name="drawer_close">Cerrar el Navigation Drawer</string>
+ <string name="edit">Editar</string>
+ <string name="my_keys">Mis claves</string>
+ <string name="label_secret_key">Claves secretas</string>
+ <string name="secret_key_yes">disponible</string>
+ <string name="secret_key_no">no disponible</string>
+ <string name="section_uids_to_sign">IDs de usuario para firmar</string>
+ <string name="progress_re_adding_certs">Nueva aplicación de certificados</string>
+ <!--hints-->
+ <string name="encrypt_content_edit_text_hint">Escribe aquí el mensaje que quieras cifrar...</string>
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-et/strings.xml b/OpenPGP-Keychain/src/main/res/values-et/strings.xml
new file mode 100644
index 000000000..04570b4b6
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-et/strings.xml
@@ -0,0 +1,123 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <string name="title_manage_public_keys">Kontaktid</string>
+ <string name="title_manage_secret_keys">Salajased võtmed</string>
+ <string name="title_select_recipients">Vali avalik võti</string>
+ <string name="title_select_secret_key">Vali salajane võti</string>
+ <string name="title_encrypt">Krüpteeri</string>
+ <string name="title_decrypt">Dekrüpteeri</string>
+ <string name="title_authentication">Salasõne</string>
+ <string name="title_create_key">Loo võti</string>
+ <string name="title_edit_key">Muuda võtit</string>
+ <string name="title_preferences">Seaded</string>
+ <string name="title_api_registered_apps">Registreeritud rakendused</string>
+ <string name="title_key_server_preference">Võtmeserveri seaded</string>
+ <string name="title_set_passphrase">Määra salasõne</string>
+ <string name="title_send_email">Saada kiri...</string>
+ <string name="title_import_keys">Impordi võtmeid</string>
+ <string name="title_export_key">Ekspordi võti</string>
+ <string name="title_export_keys">Ekspordi võtmed</string>
+ <string name="title_key_not_found">Võtit ei leitud</string>
+ <string name="title_key_server_query">Päri võtmeserverist</string>
+ <string name="title_send_key">Lae võtmeserverisse</string>
+ <string name="title_unknown_signature_key">Võõras allkirjastamise võti</string>
+ <string name="title_help">Abi</string>
+ <!--section-->
+ <string name="section_user_ids">Kasutaja ID-d</string>
+ <string name="section_keys">Võtmed</string>
+ <string name="section_general">Üldine</string>
+ <string name="section_defaults">Vaikeseaded</string>
+ <!--button-->
+ <string name="btn_sign">Allkirjasta</string>
+ <string name="btn_decrypt">Dekrüpteeri</string>
+ <string name="btn_select_encrypt_keys">Vali saajad</string>
+ <string name="btn_save">Salvesta</string>
+ <string name="btn_do_not_save">Katkesta</string>
+ <string name="btn_delete">Kustuta</string>
+ <string name="btn_set_passphrase">Määra salasõne</string>
+ <string name="btn_search">Otsi</string>
+ <string name="btn_export_to_server">Saada võtmeserverisse</string>
+ <string name="btn_next">Järgmine</string>
+ <string name="btn_back">Tagasi</string>
+ <!--menu-->
+ <string name="menu_preferences">Seaded</string>
+ <string name="menu_delete_key">Kustuta võti</string>
+ <string name="menu_create_key">Loo võti</string>
+ <string name="menu_search">Otsi</string>
+ <string name="menu_key_server">Võtmeserver...</string>
+ <string name="menu_update_key">Uuenda võtmeserverist</string>
+ <string name="menu_export_key_to_server">Saada võtmeserverisse</string>
+ <string name="menu_share">Jaga...</string>
+ <string name="menu_sign_key">Allkirjasta võti</string>
+ <!--label-->
+ <string name="label_sign">Allkirjasta</string>
+ <string name="label_message">Sõnum</string>
+ <string name="label_file">Fail</string>
+ <string name="label_no_passphrase">Salasõnet pole</string>
+ <string name="label_passphrase">Salasõne</string>
+ <string name="label_passphrase_again">Uuesti</string>
+ <string name="label_algorithm">Algoritm</string>
+ <string name="label_select_public_keys">Saajad</string>
+ <string name="label_delete_after_encryption">Kustuta peale šifreerimist</string>
+ <string name="label_hash_algorithm">Räsialgoritm</string>
+ <string name="label_asymmetric">Avalik võti</string>
+ <string name="label_symmetric">Salasõne</string>
+ <string name="label_passphrase_cache_ttl">Salasõne puhverdus</string>
+ <string name="label_key_servers">Võtmeserverid</string>
+ <string name="label_creation">Loodud</string>
+ <string name="label_expiry">Aegub</string>
+ <string name="label_usage">Kasutusvaldkond</string>
+ <string name="label_key_size">Võtmepikkus</string>
+ <string name="label_name">Nimi</string>
+ <string name="label_comment">Kommentaar</string>
+ <string name="label_email">E-mail</string>
+ <string name="unknown_status"></string>
+ <string name="expired">aegunud</string>
+ <string name="fingerprint">Sõrmejälg:</string>
+ <string name="secret_key">Salajane võti:</string>
+ <!--choice-->
+ <string name="choice_sign_only">Ainult allkirjastamine</string>
+ <string name="choice_encrypt_only">Ainult krüpteerimine</string>
+ <string name="choice_sign_and_encrypt">Allkirjastamine ja krüpteerimine</string>
+ <string name="choice_15secs">15 sekundit</string>
+ <string name="choice_1min">1 minut</string>
+ <string name="choice_3mins">3 minutit</string>
+ <string name="choice_5mins">5 minutit</string>
+ <string name="choice_10mins">10 minutit</string>
+ <string name="choice_20mins">20 minutit</string>
+ <string name="choice_40mins">40 minutit</string>
+ <string name="choice_1hour">1 tund</string>
+ <string name="choice_2hours">2 tundi</string>
+ <string name="choice_4hours">4 tundi</string>
+ <string name="choice_8hours">8 tundi</string>
+ <string name="dsa">DSA</string>
+ <string name="elgamal">ElGamal</string>
+ <string name="rsa">RSA</string>
+ <string name="filemanager_title_open">Ava...</string>
+ <string name="warning">Hoiatus</string>
+ <string name="error">Viga</string>
+ <string name="error_message">Viga: %s</string>
+ <!--sentences-->
+ <string name="wrong_passphrase">Vale salasõne</string>
+ <string name="set_a_passphrase">Määra enne salasõne.</string>
+ <string name="passphrases_do_not_match">Salasõned ei ühti.</string>
+ <string name="passphrase_must_not_be_empty">Tühi salasõne pole lubatud.</string>
+ <string name="passphrase_for_symmetric_encryption">Sümmeetriline krüpteering</string>
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <!--progress dialogs, usually ending in '…'-->
+ <!--action strings-->
+ <!--key bit length selections-->
+ <!--compression-->
+ <!--Help-->
+ <!--Import-->
+ <!--Intent labels-->
+ <!--Remote API-->
+ <!--Share-->
+ <!--Key list-->
+ <!--Key view-->
+ <!--Navigation Drawer-->
+ <!--hints-->
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-fa-rIR/strings.xml b/OpenPGP-Keychain/src/main/res/values-fa-rIR/strings.xml
new file mode 100644
index 000000000..3d00a143f
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-fa-rIR/strings.xml
@@ -0,0 +1,27 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <!--section-->
+ <!--button-->
+ <!--menu-->
+ <!--label-->
+ <string name="unknown_status"></string>
+ <!--choice-->
+ <!--sentences-->
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <!--progress dialogs, usually ending in '…'-->
+ <!--action strings-->
+ <!--key bit length selections-->
+ <!--compression-->
+ <!--Help-->
+ <!--Import-->
+ <!--Intent labels-->
+ <!--Remote API-->
+ <!--Share-->
+ <!--Key list-->
+ <!--Key view-->
+ <!--Navigation Drawer-->
+ <!--hints-->
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-fr/strings.xml b/OpenPGP-Keychain/src/main/res/values-fr/strings.xml
index aa9b59287..6c0d526d4 100644
--- a/OpenPGP-Keychain/src/main/res/values-fr/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-fr/strings.xml
@@ -13,9 +13,10 @@
<string name="title_preferences">Préférences</string>
<string name="title_api_registered_apps">Applications enregistrées</string>
<string name="title_key_server_preference">Préférences du serveur de clefs</string>
- <string name="title_change_passphrase">Changer la phrase de passe</string>
+ <string name="title_change_passphrase">Modifier la phrase de passe</string>
<string name="title_set_passphrase">Définir la phrase de passe</string>
- <string name="title_send_email">Envoyer un courriel…</string>
+ <string name="title_send_email">Envoyer un courriel...</string>
+ <string name="title_send_file">Envoyer un fichier...</string>
<string name="title_encrypt_to_file">Chiffrer vers un fichier</string>
<string name="title_decrypt_to_file">Déchiffrer vers un fichier</string>
<string name="title_import_keys">importer des clefs</string>
@@ -61,8 +62,10 @@
<string name="btn_next">Suivant</string>
<string name="btn_back">Retour</string>
<string name="btn_clipboard">Presse-papiers</string>
- <string name="btn_share">Partager avec…</string>
+ <string name="btn_share">Partager avec...</string>
<string name="btn_lookup_key">Rechercher la clef</string>
+ <string name="btn_encryption_advanced_settings_show">Afficher les paramètres avancés</string>
+ <string name="btn_encryption_advanced_settings_hide">Masquer les paramètres avancés</string>
<!--menu-->
<string name="menu_preferences">Paramètres</string>
<string name="menu_help">Aide</string>
@@ -71,19 +74,21 @@
<string name="menu_import">Importer</string>
<string name="menu_import_from_nfc">Importer avec NFC</string>
<string name="menu_export_keys">Exporter toutes les clefs</string>
+ <string name="menu_export_secret_keys">Exporter toutes les clefs secrètes</string>
<string name="menu_export_key">Exporter vers un fichier</string>
<string name="menu_delete_key">Supprimer la clef</string>
<string name="menu_create_key">Créer une clef</string>
<string name="menu_create_key_expert">Créer une clef (expert)</string>
<string name="menu_search">Rechercher</string>
- <string name="menu_key_server">Importer depuis le serveur de clefs</string>
+ <string name="menu_import_from_key_server">Serveur de clefs</string>
+ <string name="menu_key_server">Serveur de clefs...</string>
<string name="menu_update_key">Mettre à jour depuis le serveur de clefs</string>
<string name="menu_export_key_to_server">Téléverser vers le serveur de clefs</string>
- <string name="menu_share">Partager</string>
- <string name="menu_share_title_fingerprint">Partager l\'empreinte…</string>
- <string name="menu_share_title">Partager la clef entière…</string>
- <string name="menu_share_default_fingerprint">avec…</string>
- <string name="menu_share_default">avec…</string>
+ <string name="menu_share">Partager...</string>
+ <string name="menu_share_title_fingerprint">Partager l\'empreinte...</string>
+ <string name="menu_share_title">Partager la clef entière...</string>
+ <string name="menu_share_default_fingerprint">avec...</string>
+ <string name="menu_share_default">avec...</string>
<string name="menu_share_qr_code">par un code QR</string>
<string name="menu_share_qr_code_fingerprint">par un code QR</string>
<string name="menu_share_nfc">par la NFC</string>
@@ -91,7 +96,8 @@
<string name="menu_sign_key">Signer la clef</string>
<string name="menu_beam_preferences">Paramètres Beam</string>
<string name="menu_key_edit_cancel">Annuler</string>
- <string name="menu_encrypt_to">Chiffrer vers…</string>
+ <string name="menu_encrypt_to">Chiffrer vers...</string>
+ <string name="menu_select_all">Tout sélectionner</string>
<!--label-->
<string name="label_sign">Signer</string>
<string name="label_message">Message</string>
@@ -104,6 +110,7 @@
<string name="label_select_public_keys">Destinataires</string>
<string name="label_delete_after_encryption">Supprimer après le chiffrement</string>
<string name="label_delete_after_decryption">Supprimer après le chiffrement</string>
+ <string name="label_share_after_encryption">Partager après chiffrement</string>
<string name="label_encryption_algorithm">Algorithme de chiffrement</string>
<string name="label_hash_algorithm">Algorithme de hachage</string>
<string name="label_asymmetric">Clef publique</string>
@@ -122,9 +129,12 @@
<string name="label_name">Nom</string>
<string name="label_comment">Commentaire</string>
<string name="label_email">Courriel</string>
+ <string name="label_sign_user_id">Signer l\'ID utilisateur</string>
+ <string name="label_sign_email">Signer le courriel</string>
<string name="label_send_key">Téléverser la clef vers le serveur de clefs choisi après certification</string>
<string name="label_fingerprint">Empreinte</string>
<string name="select_keys_button_default">Choisir</string>
+ <string name="expiry_date_dialog_title">Définir une date d\'expiration</string>
<plurals name="select_keys_button">
<item quantity="one">%d choisie</item>
<item quantity="other">%d choisies</item>
@@ -132,11 +142,17 @@
<string name="user_id_no_name">&lt;aucun nom&gt;</string>
<string name="none">&lt;aucune&gt;</string>
<string name="no_key">&lt;pas de clef&gt;</string>
+ <string name="no_email">&lt;aucun courriel&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">peut chiffrer</string>
<string name="can_sign">peut signer</string>
<string name="expired">expiré</string>
<string name="revoked">révoquée</string>
+ <string name="user_id">ID utilisateur</string>
+ <plurals name="n_contacts">
+ <item quantity="one">1 contact</item>
+ <item quantity="other">%d contacts</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="one">%d serveur de clefs</item>
<item quantity="other">%d serveurs de clefs</item>
@@ -163,7 +179,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">Ouvrir…</string>
+ <string name="filemanager_title_open">Ouvrir...</string>
<string name="warning">Avertissement</string>
<string name="error">Erreur</string>
<string name="error_message">Erreur : %s</string>
@@ -192,6 +208,9 @@
<string name="key_deletion_confirmation">Voulez-vous vraiment supprimer la clef %s ?\nVous ne pourrez pas la restituer !</string>
<string name="key_deletion_confirmation_multi">Voulez-vous vraiment supprimer toutes les clefs choisies ?\nCeci est irréversible !</string>
<string name="secret_key_deletion_confirmation">Voulez-vous vraiment supprimer la clef SECRÈTE %s ?\nVous ne pourrez pas la restituer !</string>
+ <string name="public_key_deletetion_confirmation">Voulez-vous vraiment supprimer la clef PUBLIQUE « %s » ?\nVous ne pourrez pas la restituer !</string>
+ <string name="secret_key_delete_text">Supprimer les clefs privées ?</string>
+ <string name="also_export_secret_keys">Exporter aussi les clefs secrètes?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">%d clef ajoutée avec succès</item>
<item quantity="other">%d clefs ajoutées avec succès</item>
@@ -213,6 +232,7 @@
<string name="keys_exported">%d clefs exportées avec succès.</string>
<string name="no_keys_exported">Aucune clef exportée.</string>
<string name="key_creation_el_gamal_info">Note : seules les sous-clefs prennent en charge ElGamal, et pour ElGamal la taille de clef la plus proche de 1 536, 2 048, 3 072, 4 096 ou 8 192 sera utilisée.</string>
+ <string name="key_creation_weak_rsa_info">Note : générer des clefs RSA d\'une longueur de 1024 bits ou moins est considéré non sécuritaire et est désactivé pour la génération de nouvelles clefs.</string>
<string name="key_not_found">Clef %08X introuvable.</string>
<plurals name="keys_found">
<item quantity="one">%d clef trouvée.</item>
@@ -244,6 +264,7 @@
<string name="error_master_key_must_not_be_el_gamal">la clef maîtresse ne peut être une clef ElGama</string>
<string name="error_unknown_algorithm_choice">choix d\'algorhitme inconnu</string>
<string name="error_user_id_needs_a_name">vous devez spécifier un nom</string>
+ <string name="error_user_id_no_email">aucun courriel trouvé</string>
<string name="error_user_id_needs_an_email_address">vous devez spécifier une adresse courriel</string>
<string name="error_key_needs_a_user_id">vous avez besoin d\'au moins un ID utilisateur</string>
<string name="error_main_user_id_must_not_be_empty">l\'ID utilisateur principal ne doit pas être vide</string>
@@ -269,46 +290,56 @@
<string name="error_keyserver_insufficient_query">Requête serveur insuffisante</string>
<string name="error_keyserver_query">Échec lors de l\'interrogation du serveur de clefs</string>
<string name="error_keyserver_too_many_responses">Trop de réponses</string>
+ <string name="error_import_file_no_content">Le fichier n\'a pas de contenu</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>
<plurals name="error_can_not_delete_info">
<item quantity="one">Veuillez le supprimer depuis l\'écran « Mes Clefs »!</item>
<item quantity="other">Veuillez les supprimer depuis l\'écran « Mes Clefs »!</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="one">une partie du fichier chargé est un objet OpenPGP valide mais pas une clef OpenPGP</item>
+ <item quantity="other">certaines parties du fichier chargé sont des objets OpenPGP valides mais pas des clefs OpenPGP</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">fait.</string>
- <string name="progress_saving">sauvegarde…</string>
- <string name="progress_importing">importation…</string>
- <string name="progress_exporting">exportation…</string>
- <string name="progress_generating">génération de la clef, ceci peut prendre jusqu\'à 3 minutes…</string>
- <string name="progress_building_key">assemblage de la clef…</string>
- <string name="progress_preparing_master_key">préparation de la clef maîtresse…</string>
- <string name="progress_certifying_master_key">certification de la clef maîtresse…</string>
- <string name="progress_building_master_key">assemblage du trousseau maître…</string>
- <string name="progress_adding_sub_keys">ajout des sous-clefs…</string>
- <string name="progress_saving_key_ring">sauvegarde de la clef…</string>
+ <string name="progress_done">Terminé.</string>
+ <string name="progress_cancel">Annuler</string>
+ <string name="progress_saving">sauvegarde...</string>
+ <string name="progress_importing">importation...</string>
+ <string name="progress_exporting">exportation...</string>
+ <string name="progress_building_key">assemblage de la clef...</string>
+ <string name="progress_preparing_master_key">préparation de la clef maîtresse...</string>
+ <string name="progress_certifying_master_key">certification de la clef maîtresse...</string>
+ <string name="progress_building_master_key">assemblage du trousseau maître...</string>
+ <string name="progress_adding_sub_keys">ajout des sous-clefs...</string>
+ <string name="progress_saving_key_ring">sauvegarde de la clef...</string>
<plurals name="progress_exporting_key">
- <item quantity="one">exportation de la clef…</item>
- <item quantity="other">exportation des clefs…</item>
+ <item quantity="one">exportation de la clef...</item>
+ <item quantity="other">exportation des clefs...</item>
+ </plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">génération de la clef, ceci peut prendre jusqu\'à 3 min...</item>
+ <item quantity="other">génération des clefs, ceci peut prendre jusqu\'à 3 min...</item>
</plurals>
- <string name="progress_extracting_signature_key">extraction de la clef de signature…</string>
- <string name="progress_extracting_key">extraction de la clef…</string>
- <string name="progress_preparing_streams">préparation des flux…</string>
- <string name="progress_encrypting">chiffrement des données…</string>
- <string name="progress_decrypting">déchiffrement des données…</string>
- <string name="progress_preparing_signature">préparation de la signature…</string>
- <string name="progress_generating_signature">génération de la signature…</string>
- <string name="progress_processing_signature">traitement de la signature…</string>
- <string name="progress_verifying_signature">vérification de la signature…</string>
- <string name="progress_signing">signature…</string>
- <string name="progress_reading_data">lecture des données…</string>
- <string name="progress_finding_key">recherche de la clef…</string>
- <string name="progress_decompressing_data">décompression des données…</string>
- <string name="progress_verifying_integrity">vérification de l\'intégrité…</string>
- <string name="progress_deleting_securely">suppression sûre de « %s »…</string>
- <string name="progress_querying">interrogation…</string>
+ <string name="progress_extracting_signature_key">extraction de la clef de signature...</string>
+ <string name="progress_extracting_key">extraction de la clef...</string>
+ <string name="progress_preparing_streams">préparation des flux...</string>
+ <string name="progress_encrypting">chiffrement des données...</string>
+ <string name="progress_decrypting">déchiffrement des données...</string>
+ <string name="progress_preparing_signature">préparation de la signature...</string>
+ <string name="progress_generating_signature">génération de la signature...</string>
+ <string name="progress_processing_signature">traitement de la signature...</string>
+ <string name="progress_verifying_signature">vérification de la signature...</string>
+ <string name="progress_signing">signature...</string>
+ <string name="progress_reading_data">lecture des données...</string>
+ <string name="progress_finding_key">recherche de la clef...</string>
+ <string name="progress_decompressing_data">décompression des données...</string>
+ <string name="progress_verifying_integrity">vérification de l\'intégrité...</string>
+ <string name="progress_deleting_securely">suppression sûre de « %s »...</string>
+ <string name="progress_querying">interrogation...</string>
<!--action strings-->
<string name="hint_public_keys">Rechercher des clefs publiques</string>
<string name="hint_secret_keys">Rechercher des clefs secrètes</string>
- <string name="action_share_key_with">Partager la clef avec…</string>
+ <string name="action_share_key_with">Partager la clef avec...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_1024">1024</string>
@@ -319,6 +350,7 @@
<string name="compression_very_slow">très lent</string>
<!--Help-->
<string name="help_tab_start">Commencer</string>
+ <string name="help_tab_faq">FAQ</string>
<string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Journal des changements</string>
<string name="help_tab_about">À propos de</string>
@@ -346,6 +378,8 @@
<string name="intent_send_decrypt">Déchiffrer avec OpenKeychain</string>
<!--Remote API-->
<string name="api_no_apps">Aucune application enregistrée !\n\nLes applications tierces peuvent demander l\'accès à OpenKeychain. Après avoir autorisé l\'accès, elles seront listées ici.</string>
+ <string name="api_settings_show_info">Afficher les informations avancées</string>
+ <string name="api_settings_hide_info">Masquer les informations avancées</string>
<string name="api_settings_show_advanced">Afficher les paramètres avancés</string>
<string name="api_settings_hide_advanced">Masquer les paramètres avancés</string>
<string name="api_settings_no_key">Aucune clef choisie</string>
@@ -355,6 +389,8 @@
<string name="api_settings_revoke">Révoquer l\'accès</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_accounts">Comptes</string>
+ <string name="api_settings_accounts_empty">Aucun compte n\'est attaché à cette application.</string>
<string name="api_register_text">L\'application affichée demande l\'accès à OpenKeychain.\nPermettre l\'accès ?\n\nAvertissement : si vous ne savez pas pourquoi cet écran est apparu, refusez l\'accès ! Vous pourrez révoquer l\'accès plus tard en utilisant l\'écran « Applications enregistrées ».</string>
<string name="api_register_allow">Permettre l\'accès</string>
<string name="api_register_disallow">Enlever l\'accès</string>
@@ -374,12 +410,13 @@
<item quantity="one">1 clef choisie</item>
<item quantity="other">%d clefs choisies</item>
</plurals>
- <string name="key_list_empty_text1">Aucune clef encore disponible…</string>
+ <string name="key_list_empty_text1">Aucune clef encore disponible...</string>
<string name="key_list_empty_text2">Vous pouvez commencer par</string>
<string name="key_list_empty_text3">ou</string>
<string name="key_list_empty_button_create">créer votre propre clef</string>
<string name="key_list_empty_button_import">Importer des clefs.</string>
<!--Key view-->
+ <string name="key_view_action_edit">Modifier cette clef</string>
<string name="key_view_action_encrypt">Chiffrer vers ce contact</string>
<string name="key_view_action_certify">Certifier la clef de ce contact</string>
<string name="key_view_tab_main">Infos</string>
@@ -393,4 +430,13 @@
<string name="nav_apps">Applis enregistrées</string>
<string name="drawer_open">Ouvrir le tiroir de navigation</string>
<string name="drawer_close">Fermer le tiroir de navigation</string>
+ <string name="edit">Modifier</string>
+ <string name="my_keys">Mes clefs</string>
+ <string name="label_secret_key">Clef secrète</string>
+ <string name="secret_key_yes">disponible</string>
+ <string name="secret_key_no">non disponible</string>
+ <string name="section_uids_to_sign">ID utilisateur pour signer</string>
+ <string name="progress_re_adding_certs">Nouvel application des certificats</string>
+ <!--hints-->
+ <string name="encrypt_content_edit_text_hint">Écrire le message à chiffrer ici...</string>
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml b/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml
index 825115bc9..23dd432a4 100644
--- a/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml
@@ -13,9 +13,10 @@
<string name="title_preferences">Preferenze</string>
<string name="title_api_registered_apps">App Registrate</string>
<string name="title_key_server_preference">Preferenze Server delle Chiavi</string>
- <string name="title_change_passphrase">Cambia Frase di Accesso</string>
+ <string name="title_change_passphrase">Cambia Frase Di Accesso</string>
<string name="title_set_passphrase">Imposta Frase di Accesso</string>
- <string name="title_send_email">Invia Mail…</string>
+ <string name="title_send_email">Invia Mail...</string>
+ <string name="title_send_file">Invia file...</string>
<string name="title_encrypt_to_file">Codifica File</string>
<string name="title_decrypt_to_file">Decodifica File</string>
<string name="title_import_keys">Importa Chiavi</string>
@@ -61,8 +62,10 @@
<string name="btn_next">Prossimo</string>
<string name="btn_back">Precedente</string>
<string name="btn_clipboard">Appunti</string>
- <string name="btn_share">Condividi con…</string>
+ <string name="btn_share">Condividi con...</string>
<string name="btn_lookup_key">Chiave di ricerca</string>
+ <string name="btn_encryption_advanced_settings_show">Mostra impostazioni avanzate</string>
+ <string name="btn_encryption_advanced_settings_hide">Nascondi impostazioni avanzate</string>
<!--menu-->
<string name="menu_preferences">Impostazioni</string>
<string name="menu_help">Aiuto</string>
@@ -71,19 +74,21 @@
<string name="menu_import">Importa</string>
<string name="menu_import_from_nfc">Importa tramite NFC</string>
<string name="menu_export_keys">Esporta tutte le chiavi</string>
+ <string name="menu_export_secret_keys">Esporta tutte le chiavi segrete</string>
<string name="menu_export_key">Esporta su un file</string>
<string name="menu_delete_key">Cancella chiave</string>
<string name="menu_create_key">Crea chiave</string>
<string name="menu_create_key_expert">Crea chiave (esperto)</string>
<string name="menu_search">Cerca</string>
- <string name="menu_key_server">Importa dal server delle chiavi</string>
+ <string name="menu_import_from_key_server">Server delle Chiavi</string>
+ <string name="menu_key_server">Server delle Chiavi...</string>
<string name="menu_update_key">Aggiorna dal server delle chiavi</string>
<string name="menu_export_key_to_server">Carica chiave nel server</string>
- <string name="menu_share">Condividi</string>
- <string name="menu_share_title_fingerprint">Condivi impronta…</string>
- <string name="menu_share_title">Condividi intera chiave…</string>
+ <string name="menu_share">Condividi...</string>
+ <string name="menu_share_title_fingerprint">Condivi impronta...</string>
+ <string name="menu_share_title">Condividi intera chiave...</string>
<string name="menu_share_default_fingerprint">con..</string>
- <string name="menu_share_default">con…</string>
+ <string name="menu_share_default">con...</string>
<string name="menu_share_qr_code">con Codice QR</string>
<string name="menu_share_qr_code_fingerprint">con Codice QR</string>
<string name="menu_share_nfc">con NFC</string>
@@ -91,7 +96,8 @@
<string name="menu_sign_key">Firma chiave</string>
<string name="menu_beam_preferences">Impostazioni Beam</string>
<string name="menu_key_edit_cancel">Annulla</string>
- <string name="menu_encrypt_to">Codifica su…</string>
+ <string name="menu_encrypt_to">Codifica su...</string>
+ <string name="menu_select_all">Seleziona tutto</string>
<!--label-->
<string name="label_sign">Firma</string>
<string name="label_message">Messaggio</string>
@@ -104,6 +110,7 @@
<string name="label_select_public_keys">Destinatari</string>
<string name="label_delete_after_encryption">Cancella Dopo Codifica</string>
<string name="label_delete_after_decryption">Cancella Dopo Decodifica</string>
+ <string name="label_share_after_encryption">Condividi Dopo la Codifica</string>
<string name="label_encryption_algorithm">Algoritmo di Codifica</string>
<string name="label_hash_algorithm">Algoritmo di Hash</string>
<string name="label_asymmetric">Chiave Pubblica</string>
@@ -122,9 +129,12 @@
<string name="label_name">Nome</string>
<string name="label_comment">Commento</string>
<string name="label_email">Email</string>
+ <string name="label_sign_user_id">Firma ID Utente</string>
+ <string name="label_sign_email">Firma email</string>
<string name="label_send_key">Carica chiave nel server delle chiavi selezionati dopo la certificazione</string>
<string name="label_fingerprint">Impronta</string>
<string name="select_keys_button_default">Seleziona</string>
+ <string name="expiry_date_dialog_title">Impostare la data di scadenza</string>
<plurals name="select_keys_button">
<item quantity="one">%d selezionato</item>
<item quantity="other">%d selezionati</item>
@@ -132,11 +142,17 @@
<string name="user_id_no_name">&lt;nessun nome&gt;</string>
<string name="none">&lt;nessuno&gt;</string>
<string name="no_key">&lt;nessuna chiave&gt;</string>
+ <string name="no_email">&lt;Nessuna Email&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">puo\'; codificare</string>
<string name="can_sign">puo\' firmare</string>
<string name="expired">scaduto</string>
<string name="revoked">revocato</string>
+ <string name="user_id">ID Utente</string>
+ <plurals name="n_contacts">
+ <item quantity="one">1 contatto</item>
+ <item quantity="other">%d contatti</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="one">%d server delle chiavi</item>
<item quantity="other">%d server delle chiavi</item>
@@ -163,7 +179,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">Apri…</string>
+ <string name="filemanager_title_open">Apri...</string>
<string name="warning">Attenzione</string>
<string name="error">Errore</string>
<string name="error_message">Errore: %s</string>
@@ -192,6 +208,9 @@
<string name="key_deletion_confirmation">Vuoi veramente eliminare la chiave \'%s\'?\nNon potrai annullare!</string>
<string name="key_deletion_confirmation_multi">Vuoi veramente eliminare le chiavi selezionate?\nNon potrai annullare!</string>
<string name="secret_key_deletion_confirmation">Vuoi veramente eliminare la chiave PRIVATA \'%s\'?\nNon potrai annullare!</string>
+ <string name="public_key_deletetion_confirmation">Vuoi veramente eliminare la chiave PUBBLICA \'%s\'?\nNon potrai annullare!</string>
+ <string name="secret_key_delete_text">Eliminare le Chiavi Segrete?</string>
+ <string name="also_export_secret_keys">Esportare anche le chiavi segrete?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">%d chiave aggiunta correttamente</item>
<item quantity="other">%d chiavi aggiunte correttamente</item>
@@ -213,6 +232,7 @@
<string name="keys_exported">%d chiavi esportate correttamente.</string>
<string name="no_keys_exported">Nessuna chiave esportata.</string>
<string name="key_creation_el_gamal_info">Nota: solo le sottochiavi supportano ElGamal, e per ElGamal verra\' usata la grandezza chiave piu\' vicina a 1536, 2048, 3072, 4096 o 8192.</string>
+ <string name="key_creation_weak_rsa_info">Nota: la generazione di chiavi RSA con lunghezza pari a 1024 bit o inferiore è considerata non sicura ed è disabilitata per la generazione di nuove chiavi.</string>
<string name="key_not_found">Impossibile trovare la chiave %08X.</string>
<plurals name="keys_found">
<item quantity="one">Trovata %d chiave.</item>
@@ -244,6 +264,7 @@
<string name="error_master_key_must_not_be_el_gamal">La chiave principale non puo\' essere ElGamal</string>
<string name="error_unknown_algorithm_choice">opzione algoritmo sconosciuta</string>
<string name="error_user_id_needs_a_name">devi specificare un nome</string>
+ <string name="error_user_id_no_email">Nessuna email trovata</string>
<string name="error_user_id_needs_an_email_address">devi specificare un indirizzo email</string>
<string name="error_key_needs_a_user_id">necessario almeno un id utente</string>
<string name="error_main_user_id_must_not_be_empty">id utente principale non puo\' essere vuoto</string>
@@ -269,46 +290,56 @@
<string name="error_keyserver_insufficient_query">Query di server insufficiente</string>
<string name="error_keyserver_query">Interrogazione del server delle chiavi fallita</string>
<string name="error_keyserver_too_many_responses">Troppi responsi</string>
+ <string name="error_import_file_no_content">Il File non ha contenuti</string>
+ <string name="error_generic_report_bug">Si è verificato un errore generico, si prega di creare una nuova segnalazione di errore per OpenKeychain.</string>
<plurals name="error_can_not_delete_info">
<item quantity="one">Per favore cancellala dalla schermata \'Mie Chavi\'</item>
<item quantity="other">Per favore cancellatele dalla schermata \'Mie Chavi\'</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <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>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">fatto.</string>
- <string name="progress_saving">salvataggio…</string>
- <string name="progress_importing">importazione…</string>
- <string name="progress_exporting">esportazione…</string>
- <string name="progress_generating">generazione chiave, richiede fino a 3 minuti…</string>
- <string name="progress_building_key">fabbricazione chiave…</string>
- <string name="progress_preparing_master_key">preparazione chiave principale…</string>
- <string name="progress_certifying_master_key">certificazione chiave principale…</string>
- <string name="progress_building_master_key">fabbricazione portachiavi principale…</string>
- <string name="progress_adding_sub_keys">aggiunta sottochiavi…</string>
- <string name="progress_saving_key_ring">salvataggio chiavi…</string>
+ <string name="progress_done">Fatto.</string>
+ <string name="progress_cancel">Annulla</string>
+ <string name="progress_saving">salvataggio...</string>
+ <string name="progress_importing">importazione...</string>
+ <string name="progress_exporting">esportazione...</string>
+ <string name="progress_building_key">fabbricazione chiave...</string>
+ <string name="progress_preparing_master_key">preparazione chiave principale...</string>
+ <string name="progress_certifying_master_key">certificazione chiave principale...</string>
+ <string name="progress_building_master_key">fabbricazione portachiavi principale...</string>
+ <string name="progress_adding_sub_keys">aggiunta sottochiavi...</string>
+ <string name="progress_saving_key_ring">salvataggio chiavi...</string>
<plurals name="progress_exporting_key">
- <item quantity="one">esportazione chiave…</item>
- <item quantity="other">esportazione chiavi…</item>
+ <item quantity="one">esportazione chiave...</item>
+ <item quantity="other">esportazione chiavi...</item>
+ </plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">generazione chiave, sono necessari fino a 3 minuti...</item>
+ <item quantity="other">generazione chiavi, sono necessari fino a 3 minuti...</item>
</plurals>
- <string name="progress_extracting_signature_key">estrazione chiavi di firma…</string>
- <string name="progress_extracting_key">estrazione chiave…</string>
- <string name="progress_preparing_streams">preparazione flussi…</string>
- <string name="progress_encrypting">codifica dati…</string>
- <string name="progress_decrypting">decodifica dati…</string>
- <string name="progress_preparing_signature">preparazione firma…</string>
- <string name="progress_generating_signature">generazione firma…</string>
- <string name="progress_processing_signature">elaborazione firma…</string>
- <string name="progress_verifying_signature">verifica firma…</string>
- <string name="progress_signing">firma…</string>
- <string name="progress_reading_data">lettura dati…</string>
- <string name="progress_finding_key">ricerca chiave…</string>
- <string name="progress_decompressing_data">decompressione dati…</string>
- <string name="progress_verifying_integrity">verifica integrita\'…</string>
- <string name="progress_deleting_securely">eliminazione sicura di \'%s\'…</string>
- <string name="progress_querying">interrogazione…</string>
+ <string name="progress_extracting_signature_key">estrazione chiavi di firma...</string>
+ <string name="progress_extracting_key">estrazione chiave...</string>
+ <string name="progress_preparing_streams">preparazione flussi...</string>
+ <string name="progress_encrypting">codifica dati...</string>
+ <string name="progress_decrypting">decodifica dati...</string>
+ <string name="progress_preparing_signature">preparazione firma...</string>
+ <string name="progress_generating_signature">generazione firma...</string>
+ <string name="progress_processing_signature">elaborazione firma...</string>
+ <string name="progress_verifying_signature">verifica firma...</string>
+ <string name="progress_signing">firma...</string>
+ <string name="progress_reading_data">lettura dati...</string>
+ <string name="progress_finding_key">ricerca chiave...</string>
+ <string name="progress_decompressing_data">decompressione dati...</string>
+ <string name="progress_verifying_integrity">verifica integrita\'...</string>
+ <string name="progress_deleting_securely">eliminazione sicura di \'%s\'...</string>
+ <string name="progress_querying">interrogazione...</string>
<!--action strings-->
<string name="hint_public_keys">Ricerca Chiavi Pubbliche</string>
<string name="hint_secret_keys">Cerca Chiave Privata</string>
- <string name="action_share_key_with">Condividi chiave con…</string>
+ <string name="action_share_key_with">Condividi chiave con...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_1024">1024</string>
@@ -319,6 +350,7 @@
<string name="compression_very_slow">molto lento</string>
<!--Help-->
<string name="help_tab_start">Inizia</string>
+ <string name="help_tab_faq">FAQ</string>
<string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Novita\'</string>
<string name="help_tab_about">Info</string>
@@ -374,12 +406,13 @@
<item quantity="one">1 chiave selezionata.</item>
<item quantity="other">%d chiavi selezionate.</item>
</plurals>
- <string name="key_list_empty_text1">Nessuna chiave disponibile…</string>
+ <string name="key_list_empty_text1">Nessuna chiave disponibile...</string>
<string name="key_list_empty_text2">Puoi iniziare da</string>
<string name="key_list_empty_text3">o</string>
<string name="key_list_empty_button_create">creazione della tua chiave</string>
<string name="key_list_empty_button_import">importazione chiavi.</string>
<!--Key view-->
+ <string name="key_view_action_edit">Modifica chiave</string>
<string name="key_view_action_encrypt">Codifica a questo contatto</string>
<string name="key_view_action_certify">Certifica la chiave di questo contatto</string>
<string name="key_view_tab_main">Info</string>
@@ -393,4 +426,13 @@
<string name="nav_apps">App Registrate</string>
<string name="drawer_open">Apri drawer di navigazione</string>
<string name="drawer_close">Chiudi drawer di navigazione</string>
+ <string name="edit">Modifica</string>
+ <string name="my_keys">Le Mie Chiavi</string>
+ <string name="label_secret_key">Chiave Segreta</string>
+ <string name="secret_key_yes">disponibile</string>
+ <string name="secret_key_no">non disponibile</string>
+ <string name="section_uids_to_sign">ID Utente da firmare</string>
+ <string name="progress_re_adding_certs">Riapplicazione certificati</string>
+ <!--hints-->
+ <string name="encrypt_content_edit_text_hint">Scrivi qui il messaggio da codificare...</string>
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-ja/strings.xml b/OpenPGP-Keychain/src/main/res/values-ja/strings.xml
index 97d5a72f4..f28f73262 100644
--- a/OpenPGP-Keychain/src/main/res/values-ja/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-ja/strings.xml
@@ -15,7 +15,8 @@
<string name="title_key_server_preference">鍵サーバ設定</string>
<string name="title_change_passphrase">パスフレーズの変更</string>
<string name="title_set_passphrase">パスフレーズの設定</string>
- <string name="title_send_email">メールの送信…</string>
+ <string name="title_send_email">メールの送信...</string>
+ <string name="title_send_file">ファイルの送信...</string>
<string name="title_encrypt_to_file">暗号化してファイルに</string>
<string name="title_decrypt_to_file">復号化してファイルに</string>
<string name="title_import_keys">鍵のインポート</string>
@@ -61,8 +62,10 @@
<string name="btn_next">次</string>
<string name="btn_back">戻る</string>
<string name="btn_clipboard">クリップボード</string>
- <string name="btn_share">共有…</string>
+ <string name="btn_share">...で共有</string>
<string name="btn_lookup_key">鍵検出</string>
+ <string name="btn_encryption_advanced_settings_show">拡張設定を表示</string>
+ <string name="btn_encryption_advanced_settings_hide">拡張設定を隠す</string>
<!--menu-->
<string name="menu_preferences">設定</string>
<string name="menu_help">ヘルプ</string>
@@ -71,19 +74,21 @@
<string name="menu_import">インポート</string>
<string name="menu_import_from_nfc">NFCからインポート</string>
<string name="menu_export_keys">すべての鍵のエクスポート</string>
+ <string name="menu_export_secret_keys">すべての秘密鍵のエクスポート</string>
<string name="menu_export_key">ファイルへのエクスポート</string>
<string name="menu_delete_key">鍵の削除</string>
<string name="menu_create_key">鍵の生成</string>
<string name="menu_create_key_expert">鍵の生成(上級)</string>
<string name="menu_search">検索</string>
- <string name="menu_key_server">鍵サーバからのインポート</string>
+ <string name="menu_import_from_key_server">鍵サーバ</string>
+ <string name="menu_key_server">鍵サーバ...</string>
<string name="menu_update_key">鍵サーバからの更新</string>
<string name="menu_export_key_to_server">鍵サーバへのアップロード</string>
- <string name="menu_share">共有</string>
- <string name="menu_share_title_fingerprint">指紋の共有…</string>
- <string name="menu_share_title">すべての鍵の共有…</string>
- <string name="menu_share_default_fingerprint">…(指紋)</string>
- <string name="menu_share_default">…(鍵)</string>
+ <string name="menu_share">共有...</string>
+ <string name="menu_share_title_fingerprint">指紋の共有...</string>
+ <string name="menu_share_title">すべての鍵の共有...</string>
+ <string name="menu_share_default_fingerprint">...(指紋)</string>
+ <string name="menu_share_default">...(鍵)</string>
<string name="menu_share_qr_code">QRコードで共有(鍵)</string>
<string name="menu_share_qr_code_fingerprint">QRコードで共有(指紋)</string>
<string name="menu_share_nfc">NFCで共有</string>
@@ -91,7 +96,8 @@
<string name="menu_sign_key">鍵を署名</string>
<string name="menu_beam_preferences">Beamの設定</string>
<string name="menu_key_edit_cancel">キャンセル</string>
- <string name="menu_encrypt_to">暗号化…</string>
+ <string name="menu_encrypt_to">暗号化...</string>
+ <string name="menu_select_all">すべて選択</string>
<!--label-->
<string name="label_sign">署名</string>
<string name="label_message">メッセージ</string>
@@ -104,6 +110,7 @@
<string name="label_select_public_keys">受信者</string>
<string name="label_delete_after_encryption">暗号化後に削除</string>
<string name="label_delete_after_decryption">復号化後に削除</string>
+ <string name="label_share_after_encryption">暗号化して共有</string>
<string name="label_encryption_algorithm">暗号化アルゴリズム</string>
<string name="label_hash_algorithm">ハッシュアルゴリズム</string>
<string name="label_asymmetric">公開鍵</string>
@@ -122,20 +129,28 @@
<string name="label_name">名前</string>
<string name="label_comment">コメント</string>
<string name="label_email">Eメールアドレス</string>
+ <string name="label_sign_user_id">署名ユーザーID</string>
+ <string name="label_sign_email">メールを署名</string>
<string name="label_send_key">証明後選択した鍵サーバに鍵をアップロード</string>
<string name="label_fingerprint">指紋</string>
<string name="select_keys_button_default">選択</string>
+ <string name="expiry_date_dialog_title">期限日時を設定</string>
<plurals name="select_keys_button">
<item quantity="other">%d を選択</item>
</plurals>
<string name="user_id_no_name">&lt;名前なし&gt;</string>
<string name="none">&lt;無し&gt;</string>
<string name="no_key">&lt;鍵無し&gt;</string>
+ <string name="no_email">&lt;メールなし&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">暗号化可能</string>
<string name="can_sign">署名可能</string>
<string name="expired">期限切れ</string>
<string name="revoked">破棄</string>
+ <string name="user_id">ユーザーID</string>
+ <plurals name="n_contacts">
+ <item quantity="other">%d個の連絡先</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="other">%d の鍵サーバ</item>
</plurals>
@@ -161,7 +176,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">開く…</string>
+ <string name="filemanager_title_open">開く...</string>
<string name="warning">注意</string>
<string name="error">エラー</string>
<string name="error_message">エラー: %s</string>
@@ -190,6 +205,9 @@
<string name="key_deletion_confirmation">鍵\'%s\'を本当に削除してもよいですか?\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>
+ <string name="secret_key_delete_text">秘密鍵を削除しますか?</string>
+ <string name="also_export_secret_keys">秘密鍵もエクスポートしますか?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="other">%d の鍵を追加しました</item>
</plurals>
@@ -207,6 +225,7 @@
<string name="keys_exported">%d の鍵をエクスポートしました。</string>
<string name="no_keys_exported">鍵をエクスポートしていません。</string>
<string name="key_creation_el_gamal_info">備考: 副鍵として ElGamalだけがサポートされ, ElGamal は鍵サイズとして1536, 2048, 3072, 4096, 8192 だけが使えます。</string>
+ <string name="key_creation_weak_rsa_info">付記: 長さ1024bitかそれ以下で生成されたRSA鍵は安全とはみなされず、新な鍵の生成は無効にされています。</string>
<string name="key_not_found">鍵 %08X は見付かりませんでした。</string>
<plurals name="keys_found">
<item quantity="other">%d の鍵を発見。</item>
@@ -236,6 +255,7 @@
<string name="error_master_key_must_not_be_el_gamal">主鍵を ElGamal にすることはできません</string>
<string name="error_unknown_algorithm_choice">未知のアルゴリズムを選択しています</string>
<string name="error_user_id_needs_a_name">名前を特定する必要があります</string>
+ <string name="error_user_id_no_email">メールが見付かりません</string>
<string name="error_user_id_needs_an_email_address">Eメールアドレスを特定する必要があります</string>
<string name="error_key_needs_a_user_id">最低でも1つのユーザIDが必要です</string>
<string name="error_main_user_id_must_not_be_empty">主ユーザIDは空にすることはできません</string>
@@ -261,44 +281,52 @@
<string name="error_keyserver_insufficient_query">サーバへのクエリーが不足しています</string>
<string name="error_keyserver_query">鍵サーバへのクエリーが失敗</string>
<string name="error_keyserver_too_many_responses">レスポンスが多すぎます</string>
+ <string name="error_import_file_no_content">ファイルに内容がありません</string>
+ <string name="error_generic_report_bug">一般エラーが発生しました、この新しいバグの情報をOpenKeychainプロジェクトに送ってください</string>
<plurals name="error_can_not_delete_info">
<item quantity="other">\'自分の鍵\'画面から削除してください!</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="other">読み込んだファイルのOpenPGPオブジェクト部分は正しいですが、OpenPGPの鍵ではありません</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
<string name="progress_done">完了。</string>
- <string name="progress_saving">保存…</string>
- <string name="progress_importing">インポート…</string>
- <string name="progress_exporting">エクスポート…</string>
- <string name="progress_generating">鍵の生成、3分ほどかかります…</string>
- <string name="progress_building_key">鍵の構築中…</string>
- <string name="progress_preparing_master_key">主鍵の準備中…</string>
- <string name="progress_certifying_master_key">主鍵の検証中…</string>
- <string name="progress_building_master_key">主鍵輪の構築中…</string>
- <string name="progress_adding_sub_keys">副鍵の追加中…</string>
- <string name="progress_saving_key_ring">鍵の保存…</string>
+ <string name="progress_cancel">キャンセル</string>
+ <string name="progress_saving">保存...</string>
+ <string name="progress_importing">インポート...</string>
+ <string name="progress_exporting">エクスポート...</string>
+ <string name="progress_building_key">鍵の構築中...</string>
+ <string name="progress_preparing_master_key">主鍵の準備中...</string>
+ <string name="progress_certifying_master_key">主鍵の検証中...</string>
+ <string name="progress_building_master_key">主鍵輪の構築中...</string>
+ <string name="progress_adding_sub_keys">副鍵の追加中...</string>
+ <string name="progress_saving_key_ring">鍵の保存...</string>
<plurals name="progress_exporting_key">
- <item quantity="other">鍵のエクスポート…</item>
+ <item quantity="other">鍵のエクスポート...</item>
+ </plurals>
+ <plurals name="progress_generating">
+ <item quantity="other">鍵の生成中、最大3分ほどかかります...</item>
</plurals>
- <string name="progress_extracting_signature_key">署名鍵の取り出し中…</string>
- <string name="progress_extracting_key">鍵の取り出し中…</string>
- <string name="progress_preparing_streams">ストリームの準備中…</string>
- <string name="progress_encrypting">データの暗号化中…</string>
- <string name="progress_decrypting">データの復号化中…</string>
- <string name="progress_preparing_signature">署名の準備中…</string>
- <string name="progress_generating_signature">署名の生成中…</string>
- <string name="progress_processing_signature">署名処理中…</string>
- <string name="progress_verifying_signature">署名の検証中…</string>
- <string name="progress_signing">署名中…</string>
- <string name="progress_reading_data">データ読み込み中…</string>
- <string name="progress_finding_key">鍵検索中…</string>
- <string name="progress_decompressing_data">データの展開中…</string>
- <string name="progress_verifying_integrity">完全性の検証中…</string>
+ <string name="progress_extracting_signature_key">署名鍵の取り出し中...</string>
+ <string name="progress_extracting_key">鍵の取り出し中...</string>
+ <string name="progress_preparing_streams">ストリームの準備中...</string>
+ <string name="progress_encrypting">データの暗号化中...</string>
+ <string name="progress_decrypting">データの復号化中...</string>
+ <string name="progress_preparing_signature">署名の準備中...</string>
+ <string name="progress_generating_signature">署名の生成中...</string>
+ <string name="progress_processing_signature">署名処理中...</string>
+ <string name="progress_verifying_signature">署名の検証中...</string>
+ <string name="progress_signing">署名中...</string>
+ <string name="progress_reading_data">データ読み込み中...</string>
+ <string name="progress_finding_key">鍵検索中...</string>
+ <string name="progress_decompressing_data">データの展開中...</string>
+ <string name="progress_verifying_integrity">完全性の検証中...</string>
<string name="progress_deleting_securely">\'%s\' を完全に削除中…</string>
- <string name="progress_querying">要求中…</string>
+ <string name="progress_querying">要求中...</string>
<!--action strings-->
<string name="hint_public_keys">公開鍵の検索</string>
<string name="hint_secret_keys">秘密鍵の検索</string>
- <string name="action_share_key_with">鍵の共有…</string>
+ <string name="action_share_key_with">...で鍵の共有</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_1024">1024</string>
@@ -309,6 +337,7 @@
<string name="compression_very_slow">とても遅い</string>
<!--Help-->
<string name="help_tab_start">開始</string>
+ <string name="help_tab_faq">FAQ</string>
<string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Changelog</string>
<string name="help_tab_about">これについて</string>
@@ -336,7 +365,7 @@
<!--Remote API-->
<string name="api_no_apps">登録されていないアプリケーション!\n\nサードパーティアプリケーションはOpenKeychainにアクセスを要求できます。アクセスを与えた後、それらはここにリストされます。</string>
<string name="api_settings_show_advanced">拡張設定を表示</string>
- <string name="api_settings_hide_advanced">拡張設定を非表示</string>
+ <string name="api_settings_hide_advanced">拡張設定を隠す</string>
<string name="api_settings_no_key">鍵が選択されていない</string>
<string name="api_settings_select_key">鍵の選択</string>
<string name="api_settings_save">保存</string>
@@ -362,12 +391,13 @@
<plurals name="key_list_selected_keys">
<item quantity="other">%d の鍵を選択。</item>
</plurals>
- <string name="key_list_empty_text1">すでにその鍵は存在しません…</string>
+ <string name="key_list_empty_text1">すでにその鍵は存在しません...</string>
<string name="key_list_empty_text2">で始める</string>
<string name="key_list_empty_text3">もしくは</string>
<string name="key_list_empty_button_create">あなた所有の鍵を作る</string>
<string name="key_list_empty_button_import">鍵のインポート。</string>
<!--Key view-->
+ <string name="key_view_action_edit">この鍵の編集</string>
<string name="key_view_action_encrypt">この連絡先を暗号化</string>
<string name="key_view_action_certify">この連絡先の鍵を検証</string>
<string name="key_view_tab_main">情報</string>
@@ -381,4 +411,13 @@
<string name="nav_apps">登録済みのアプリ</string>
<string name="drawer_open">ナビゲーションドロワーを開く</string>
<string name="drawer_close">ナビゲーションドロワーを閉める</string>
+ <string name="edit">編集</string>
+ <string name="my_keys">自分の鍵</string>
+ <string name="label_secret_key">秘密鍵</string>
+ <string name="secret_key_yes">存在する</string>
+ <string name="secret_key_no">存在しない</string>
+ <string name="section_uids_to_sign">署名に使うユーザーID</string>
+ <string name="progress_re_adding_certs">検証を再適用する</string>
+ <!--hints-->
+ <string name="encrypt_content_edit_text_hint">ここに書いたメッセージを暗号化..</string>
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-large/dimens.xml b/OpenPGP-Keychain/src/main/res/values-large/dimens.xml
new file mode 100644
index 000000000..192a4bb99
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-large/dimens.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="drawer_content_padding">240dp</dimen>
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml b/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml
index 863932a80..a7f674ea0 100644
--- a/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml
@@ -10,9 +10,8 @@
<string name="title_edit_key">Sleutel bewerken</string>
<string name="title_preferences">Instellingen</string>
<string name="title_api_registered_apps">Geregistreerde apps</string>
- <string name="title_change_passphrase">Wachtwoord wijzigen</string>
<string name="title_set_passphrase">Wachtwoord instellen</string>
- <string name="title_send_email">E-mail verzenden…</string>
+ <string name="title_send_email">E-mail verzenden...</string>
<string name="title_encrypt_to_file">Versleutelen naar bestand</string>
<string name="title_decrypt_to_file">Ontsleutelen naar bestand</string>
<string name="title_import_keys">Sleutels importeren</string>
@@ -109,7 +108,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">Openen…</string>
+ <string name="filemanager_title_open">Openen...</string>
<string name="warning">Waarschuwing</string>
<string name="error">Fout</string>
<string name="error_message">Fout: %s</string>
@@ -171,35 +170,34 @@
<string name="error_nfc_needed">Uw apparaat biedt geen ondersteuning voor NFC</string>
<string name="error_nothing_import">Niets te importeren</string>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">gereed.</string>
- <string name="progress_saving">opslaan…</string>
- <string name="progress_importing">importeren…</string>
- <string name="progress_exporting">exporteren…</string>
- <string name="progress_building_key">sleutel maken…</string>
- <string name="progress_preparing_master_key">hoofdsleutel voorbereiden…</string>
- <string name="progress_certifying_master_key">hoofdsleutel certificeren…</string>
- <string name="progress_building_master_key">hoofdsleutelbos maken…</string>
- <string name="progress_adding_sub_keys">sub-sleutels toevoegen…</string>
- <string name="progress_extracting_signature_key">ondertekeningssleutel uitpakken…</string>
- <string name="progress_extracting_key">sleutel uitpakken…</string>
- <string name="progress_preparing_streams">streams voorbereiden…</string>
- <string name="progress_encrypting">gegevens versleutelen…</string>
- <string name="progress_decrypting">gegevens ontsleutelen…</string>
- <string name="progress_preparing_signature">handtekening voorbereiden…</string>
- <string name="progress_generating_signature">handtekening genereren…</string>
- <string name="progress_processing_signature">handtekening verwerken…</string>
- <string name="progress_verifying_signature">handtekening verifiëren…</string>
- <string name="progress_signing">ondertekenen…</string>
- <string name="progress_reading_data">gegevens lezen…</string>
- <string name="progress_finding_key">sleutel opzoeken…</string>
- <string name="progress_decompressing_data">gegevens decomprimeren…</string>
- <string name="progress_verifying_integrity">integriteit verifiëren…</string>
- <string name="progress_deleting_securely">\'%s\' veilig verwijderen…</string>
- <string name="progress_querying">opvragen…</string>
+ <string name="progress_saving">opslaan...</string>
+ <string name="progress_importing">importeren...</string>
+ <string name="progress_exporting">exporteren...</string>
+ <string name="progress_building_key">sleutel maken...</string>
+ <string name="progress_preparing_master_key">hoofdsleutel voorbereiden...</string>
+ <string name="progress_certifying_master_key">hoofdsleutel certificeren...</string>
+ <string name="progress_building_master_key">hoofdsleutelbos maken...</string>
+ <string name="progress_adding_sub_keys">sub-sleutels toevoegen...</string>
+ <string name="progress_extracting_signature_key">ondertekeningssleutel uitpakken...</string>
+ <string name="progress_extracting_key">sleutel uitpakken...</string>
+ <string name="progress_preparing_streams">streams voorbereiden...</string>
+ <string name="progress_encrypting">gegevens versleutelen...</string>
+ <string name="progress_decrypting">gegevens ontsleutelen...</string>
+ <string name="progress_preparing_signature">handtekening voorbereiden...</string>
+ <string name="progress_generating_signature">handtekening genereren...</string>
+ <string name="progress_processing_signature">handtekening verwerken...</string>
+ <string name="progress_verifying_signature">handtekening verifiëren...</string>
+ <string name="progress_signing">ondertekenen...</string>
+ <string name="progress_reading_data">gegevens lezen...</string>
+ <string name="progress_finding_key">sleutel opzoeken...</string>
+ <string name="progress_decompressing_data">gegevens decomprimeren...</string>
+ <string name="progress_verifying_integrity">integriteit verifiëren...</string>
+ <string name="progress_deleting_securely">\'%s\' veilig verwijderen...</string>
+ <string name="progress_querying">opvragen...</string>
<!--action strings-->
<string name="hint_public_keys">Publieke sleutels zoeken</string>
<string name="hint_secret_keys">Privésleutels zoeken</string>
- <string name="action_share_key_with">Sleutel delen met…</string>
+ <string name="action_share_key_with">Sleutel delen met...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_1024">1024</string>
@@ -237,4 +235,5 @@
<!--Key list-->
<!--Key view-->
<!--Navigation Drawer-->
+ <!--hints-->
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-pl/strings.xml b/OpenPGP-Keychain/src/main/res/values-pl/strings.xml
new file mode 100644
index 000000000..e31216176
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-pl/strings.xml
@@ -0,0 +1,457 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <string name="title_manage_public_keys">Kontakty</string>
+ <string name="title_manage_secret_keys">Klucze prywatne</string>
+ <string name="title_select_recipients">Wybierz Klucz Publiczny</string>
+ <string name="title_select_secret_key">Wybierz Klucz Prywatny</string>
+ <string name="title_encrypt">Zaszyfruj</string>
+ <string name="title_decrypt">Odszyfruj</string>
+ <string name="title_authentication">Hasło</string>
+ <string name="title_create_key">Utwórz Klucz</string>
+ <string name="title_edit_key">Edytuj Klucz</string>
+ <string name="title_preferences">Właściwości</string>
+ <string name="title_api_registered_apps">Zarejestrowane Aplikacje</string>
+ <string name="title_key_server_preference">Właściwości serwera kluczy</string>
+ <string name="title_change_passphrase">Zmień hasło</string>
+ <string name="title_set_passphrase">Ustaw hasło</string>
+ <string name="title_send_email">Wyślij maila...</string>
+ <string name="title_send_file">Wyślij plik...</string>
+ <string name="title_encrypt_to_file">Zaszyfruj do pliku</string>
+ <string name="title_decrypt_to_file">Odszyfruj do pliku</string>
+ <string name="title_import_keys">Importuj klucze</string>
+ <string name="title_export_key">Eksportuj klucz</string>
+ <string name="title_export_keys">Eksportuj klucze</string>
+ <string name="title_key_not_found">Nie znaleziono klucza</string>
+ <string name="title_key_server_query">Wyślij zapytanie do serwera kluczy</string>
+ <string name="title_send_key">Wyślij do serwera kluczy</string>
+ <string name="title_unknown_signature_key">Nieznany klucz podpisu</string>
+ <string name="title_certify_key">Certyfikuj klucz</string>
+ <string name="title_key_details">Szczegóły klucza</string>
+ <string name="title_help">Pomoc</string>
+ <!--section-->
+ <string name="section_user_ids">Identyfikator użytkownika</string>
+ <string name="section_keys">Klucze</string>
+ <string name="section_general">Ogólne</string>
+ <string name="section_defaults">Domyślne</string>
+ <string name="section_advanced">Zaawansowane</string>
+ <string name="section_master_key">Klucz główny</string>
+ <string name="section_master_user_id">Główny identyfikator użytkownika</string>
+ <string name="section_actions">Działania</string>
+ <string name="section_certification_key">Twój klucz użyty do certyfikacji</string>
+ <string name="section_upload_key">Wyślij klucz</string>
+ <string name="section_key_server">Serwer kluczy</string>
+ <string name="section_encrypt_and_or_sign">Zaszyfruj i/lub podpisz</string>
+ <string name="section_decrypt_verify">Deszyfruj i weryfikuj</string>
+ <!--button-->
+ <string name="btn_sign">Podpisz</string>
+ <string name="btn_certify">Certyfikuj</string>
+ <string name="btn_decrypt">Odszyfruj</string>
+ <string name="btn_decrypt_verify">Deszyfruj i weryfikuj</string>
+ <string name="btn_select_encrypt_keys">Wybierz odbiorców</string>
+ <string name="btn_encrypt_file">Zaszyfruj plik</string>
+ <string name="btn_save">Zapisz</string>
+ <string name="btn_do_not_save">Anuluj</string>
+ <string name="btn_delete">Usuń</string>
+ <string name="btn_no_date">Żaden</string>
+ <string name="btn_okay">Ok</string>
+ <string name="btn_change_passphrase">Zmień hasło</string>
+ <string name="btn_set_passphrase">Ustaw hasło</string>
+ <string name="btn_search">Wyszukaj</string>
+ <string name="btn_export_to_server">Wyślij do serwera kluczy</string>
+ <string name="btn_next">Dalej</string>
+ <string name="btn_back">Wstecz</string>
+ <string name="btn_clipboard">Schowek</string>
+ <string name="btn_share">Podziel się z...</string>
+ <string name="btn_lookup_key">Klucz wyszukiwania</string>
+ <string name="btn_encryption_advanced_settings_show">Pokaż zaawanowane ustawienia</string>
+ <string name="btn_encryption_advanced_settings_hide">Ukryj zaawansowane ustawienia</string>
+ <!--menu-->
+ <string name="menu_preferences">Ustawienia</string>
+ <string name="menu_help">Pomoc</string>
+ <string name="menu_import_from_file">Zaimportuj z pliku</string>
+ <string name="menu_import_from_qr_code">Zaimportuj z kodu QR</string>
+ <string name="menu_import">Import</string>
+ <string name="menu_import_from_nfc">Zaimportuj przy użyciu NFC</string>
+ <string name="menu_export_keys">Eksportuj wszystkie klucze</string>
+ <string name="menu_export_secret_keys">Eksportuj wszystkie klucze prywatne</string>
+ <string name="menu_export_key">Eksportuj do pliku</string>
+ <string name="menu_delete_key">Usuń klucz</string>
+ <string name="menu_create_key">Stwórz klucz</string>
+ <string name="menu_create_key_expert">Stwórz klucz (tryb zaawansowany)</string>
+ <string name="menu_search">Znajdź</string>
+ <string name="menu_import_from_key_server">Serwer kluczy</string>
+ <string name="menu_key_server">Serwer kluczy...</string>
+ <string name="menu_update_key">Aktualizuj z serwera kluczy</string>
+ <string name="menu_export_key_to_server">Wyślij do serwera kluczy</string>
+ <string name="menu_share">Udostepnij...</string>
+ <string name="menu_share_title_fingerprint">Udostepnij odcisk...</string>
+ <string name="menu_share_title">Udostępnij cały klucz...</string>
+ <string name="menu_share_default_fingerprint">z...</string>
+ <string name="menu_share_default">z...</string>
+ <string name="menu_share_qr_code">za pomocą kodu QR</string>
+ <string name="menu_share_qr_code_fingerprint">za pomocą kodu QR</string>
+ <string name="menu_share_nfc">za pomocą NFC</string>
+ <string name="menu_copy_to_clipboard">Kopiuj do schowka</string>
+ <string name="menu_sign_key">Klucz podpisu</string>
+ <string name="menu_beam_preferences">Ustawienia Beam</string>
+ <string name="menu_key_edit_cancel">Anuluj</string>
+ <string name="menu_encrypt_to">Zaszyfruj do...</string>
+ <string name="menu_select_all">Wybierz wszystko</string>
+ <!--label-->
+ <string name="label_sign">Podpis</string>
+ <string name="label_message">Wiadomość</string>
+ <string name="label_file">Plik</string>
+ <string name="label_no_passphrase">Brak hasła</string>
+ <string name="label_passphrase">Hasło</string>
+ <string name="label_passphrase_again">Ponów</string>
+ <string name="label_algorithm">Algorytm</string>
+ <string name="label_ascii_armor">ASCII Armor</string>
+ <string name="label_select_public_keys">Odbiorcy</string>
+ <string name="label_delete_after_encryption">Usuń po zaszyfrowaniu</string>
+ <string name="label_delete_after_decryption">Usuń po odszyfrowaniu</string>
+ <string name="label_share_after_encryption">Udostępnij po zaszyfrowaniu</string>
+ <string name="label_encryption_algorithm">Algorytm szyfrujący</string>
+ <string name="label_hash_algorithm">Algorytm funkcji skrótu</string>
+ <string name="label_asymmetric">Klucz publiczny</string>
+ <string name="label_symmetric">Hasło</string>
+ <string name="label_passphrase_cache_ttl">Bufor haseł</string>
+ <string name="label_message_compression">Kompresja wiadomości</string>
+ <string name="label_file_compression">Kompresja plików</string>
+ <string name="label_force_v3_signature">Wymuś stare podpisy OpenPGPv3</string>
+ <string name="label_key_servers">Serwery kluczy</string>
+ <string name="label_key_id">Identyfikator klucza</string>
+ <string name="label_creation">Utworzenia</string>
+ <string name="label_expiry">Wygaśnięcia</string>
+ <string name="label_usage">Wykorzystanie</string>
+ <string name="label_key_size">Rozmiar klucza</string>
+ <string name="label_main_user_id">Identyfikator głównego użytkownika</string>
+ <string name="label_name">Imię</string>
+ <string name="label_comment">Komentarz</string>
+ <string name="label_email">Adres email</string>
+ <string name="label_sign_user_id">Identyfikator użytkownika podpisu (sign user id)</string>
+ <string name="label_sign_email">Podpisz e-mail</string>
+ <string name="label_send_key">Wyślij klucz do serwera kluczy po certyfikacji</string>
+ <string name="label_fingerprint">Odcisk</string>
+ <string name="select_keys_button_default">Wybierz</string>
+ <string name="expiry_date_dialog_title">Ustaw datę wygaśnięcia</string>
+ <plurals name="select_keys_button">
+ <item quantity="one">wybrano %d</item>
+ <item quantity="few">wybrano %d</item>
+ <item quantity="other">wybrano %d</item>
+ </plurals>
+ <string name="user_id_no_name">&lt;bez nazwy&gt;</string>
+ <string name="none">&lt;żaden&gt;</string>
+ <string name="no_key">&lt;brak klucza&gt;</string>
+ <string name="no_email">&lt;Brak adresu email&gt;</string>
+ <string name="unknown_status"></string>
+ <string name="can_encrypt">może szyfrować</string>
+ <string name="can_sign">może podpisywać</string>
+ <string name="expired">wygasły</string>
+ <string name="revoked">unieważniony</string>
+ <string name="user_id">Identyfikator użytkownika</string>
+ <plurals name="n_contacts">
+ <item quantity="one">1 kontakt</item>
+ <item quantity="few">%d kontakty</item>
+ <item quantity="other">%d kontaktów</item>
+ </plurals>
+ <plurals name="n_key_servers">
+ <item quantity="one">%d serwer kluczy</item>
+ <item quantity="few">%d serwerów kluczy</item>
+ <item quantity="other">%d serwerów kluczy</item>
+ </plurals>
+ <string name="fingerprint">Odcisk:</string>
+ <string name="secret_key">Klucz prywatny:</string>
+ <!--choice-->
+ <string name="choice_none">Żaden</string>
+ <string name="choice_sign_only">Tylko podpisz</string>
+ <string name="choice_encrypt_only">Tylko zaszyfruj</string>
+ <string name="choice_sign_and_encrypt">Podpisz i zaszyfruj</string>
+ <string name="choice_15secs">15 sekund</string>
+ <string name="choice_1min">1 minuta</string>
+ <string name="choice_3mins">3 minuty</string>
+ <string name="choice_5mins">5 minut</string>
+ <string name="choice_10mins">10 minut</string>
+ <string name="choice_20mins">20 minut</string>
+ <string name="choice_40mins">40 minut</string>
+ <string name="choice_1hour">1 godzina</string>
+ <string name="choice_2hours">2 godziny</string>
+ <string name="choice_4hours">4 godziny</string>
+ <string name="choice_8hours">8 godzin</string>
+ <string name="choice_forever">na zawsze</string>
+ <string name="dsa">DSA</string>
+ <string name="elgamal">ElGamal</string>
+ <string name="rsa">RSA</string>
+ <string name="filemanager_title_open">Otwórz...</string>
+ <string name="warning">Ostrzeżenie</string>
+ <string name="error">Błąd</string>
+ <string name="error_message">Błąd: %s</string>
+ <!--sentences-->
+ <string name="wrong_passphrase">Nieprawidłowe hasło.</string>
+ <string name="using_clipboard_content">Użycie zawartości schowka.</string>
+ <string name="set_a_passphrase">Najpierw ustaw hasło.</string>
+ <string name="no_filemanager_installed">Nie zainstalowano żadnego kompatybilnego menadżera plików.</string>
+ <string name="passphrases_do_not_match">Hasła nie pasują do siebie</string>
+ <string name="passphrase_must_not_be_empty">Puste hasła nie są dozwolone.</string>
+ <string name="passphrase_for_symmetric_encryption">Szyfrowanie symetryczne.</string>
+ <string name="passphrase_for">Podaj hasło dla \'%s\'</string>
+ <string name="file_delete_confirmation">Czy jesteś pewien że chcesz usunąć\n%s?</string>
+ <string name="file_delete_successful">Usunięto pomyślnie.</string>
+ <string name="no_file_selected">Najpierw wskaż plik.</string>
+ <string name="decryption_successful">Odszyfrowano pomyślnie.</string>
+ <string name="encryption_successful">Zaszyfrowano pomyślnie.</string>
+ <string name="encryption_to_clipboard_successful">Pomyślnie zaszyfrowano do schowka.</string>
+ <string name="enter_passphrase_twice">Podaj hasło dwukrotnie.</string>
+ <string name="select_encryption_key">Wybierz co najmniej jeden klucz szyfrujący.</string>
+ <string name="select_encryption_or_signature_key">Wybierz co najmniej jeden klucz szyfrujący lub klucz podpisujący.</string>
+ <string name="specify_file_to_encrypt_to">Wskaż, do którego pliku zapisać zaszyfrowane dane.\nOSTRZEŻENIE: Plik zostanie nadpisany, jeżeli istnieje.</string>
+ <string name="specify_file_to_decrypt_to">Wskaż, do którego pliku zapisać odszyfrowane dane.\nOSTRZEŻENIE: Plik zostanie nadpisany, jeżeli istnieje.</string>
+ <string name="specify_file_to_export_to">Wskaż, do którego pliku wyeksportować dane.\nOSTRZEŻENIE: Plik zostanie nadpisany, jeżeli istnieje.</string>
+ <string name="specify_file_to_export_secret_keys_to">Wskaż, do którego pliku zapisać eksportowane dane.\nOSTRZEŻENIE: Masz zamiar zapisać klucze PRYWATNE (tajne)\nOSTRZEŻENIE: Plik zostanie nadpisany, jeżeli istnieje.</string>
+ <string name="key_deletion_confirmation">Czy na pewno chcesz usunąć klucz \'%s\'?\nNie można cofnąć tej operacji!</string>
+ <string name="key_deletion_confirmation_multi">Czy na pewno chcesz usunąć wszystkie zaznaczone klucze?\nTej operacji nie można cofnąć!</string>
+ <string name="secret_key_deletion_confirmation">Czy na pewno chcesz usunąć klucz prywatny \'%s\'?\nNie można cofnąć tej operacji!</string>
+ <string name="public_key_deletetion_confirmation">Czy na pewno chcesz usunąć klucz publiczny \'%s\'?\nNie można cofnąć tej operacji!</string>
+ <string name="secret_key_delete_text">Usunąć klucze prywatne?</string>
+ <string name="also_export_secret_keys">Czy wyeksportować również klucze prywatne?</string>
+ <plurals name="keys_added_and_updated_1">
+ <item quantity="one">Pomyślnie dodano %d klucz</item>
+ <item quantity="few">Pomyślnie dodano %d kluczy</item>
+ <item quantity="other">Pomyślnie dodano %d kluczy</item>
+ </plurals>
+ <plurals name="keys_added_and_updated_2">
+ <item quantity="one">i zaktualizowano %d klucz.</item>
+ <item quantity="few">i zaktualizowano %d kluczy.</item>
+ <item quantity="other">i zaktualizowano %d kluczy.</item>
+ </plurals>
+ <plurals name="keys_added">
+ <item quantity="one">Pomyślnie dodano %d klucz.</item>
+ <item quantity="few">Pomyślnie dodano %d kluczy.</item>
+ <item quantity="other">Pomyślnie dodano %d kluczy.</item>
+ </plurals>
+ <plurals name="keys_updated">
+ <item quantity="one">Pomyślnie zaktualizowano %d klucz.</item>
+ <item quantity="few">Pomyślnie zaktualizowano %d kluczy.</item>
+ <item quantity="other">Pomyślnie zaktualizowano %d kluczy.</item>
+ </plurals>
+ <string name="no_keys_added_or_updated">Nie dodano ani zaktualizowano żadnych kluczy.</string>
+ <string name="key_exported">Pomyślnie wyeksportowano 1 klucz.</string>
+ <string name="keys_exported">Pomyślnie wyeksportowano %d kluczy.</string>
+ <string name="no_keys_exported">Nie wyeksportowano żadnych kluczy.</string>
+ <string name="key_creation_el_gamal_info">Uwaga: algorytm EnGamal jest obsługiwany tylko przez podklucze i użyty zostanie najbliższy rozmiar klucza z podanych: 1536, 2048, 3072, 4096, 8192.</string>
+ <string name="key_creation_weak_rsa_info">Uwaga: generowanie klucza RSA o długości 1024 bity i mniejszej jest uważane za niebezpieczne i wyłączone dla tworzenia nowych kluczy.</string>
+ <string name="key_not_found">Nie można znaleźć klucza %08X.</string>
+ <plurals name="keys_found">
+ <item quantity="one">Znaleziono %d klucz.</item>
+ <item quantity="few">Znaleziono %d kluczy.</item>
+ <item quantity="other">Znaleziono %d kluczy.</item>
+ </plurals>
+ <string name="unknown_signature">Nieznany podpis, naciśnij przycisk, aby wyszukać brakujący klucz.</string>
+ <plurals name="bad_keys_encountered">
+ <item quantity="one">Zignorowano %d niepoprawny klucz prywatny. Prawdopodobnie został wyeksportowany przy uzyciu opcji\n --export-secret-subkeys\nUpewnij się że eksportujesz go z opcją\n --export-secret-keys\nktóra jest poprawna.</item>
+ <item quantity="few">Zignorowano %d niepoprawnych kluczy prywatnych. Prawdopodobnie zostały wyeksportowane przy uzyciu opcji\n --export-secret-subkeys\nUpewnij się że eksportujesz je z opcją\n --export-secret-keys\nktóra jest poprawna.</item>
+ <item quantity="other">zignorowano %d niepoprawnych kluczy prywatnych. Prawdopodobnie zostały wyeksportowane przy uzyciu opcji\n --export-secret-subkeys\nUpewnij się że eksportujesz je z opcją\n --export-secret-keys\nktóra jest poprawna.</item>
+ </plurals>
+ <string name="key_send_success">Pomyślnie wysłano klucz na serwer</string>
+ <string name="key_sign_success">Pomyślnie podpisano klucz</string>
+ <string name="list_empty">Lista jest pusta!</string>
+ <string name="nfc_successfull">Pomyślnie wysłano klucz przez NFC!</string>
+ <string name="key_copied_to_clipboard">Klucz został skopiowany do schowka!</string>
+ <string name="key_has_already_been_signed">Klucz został już wcześniej podpisany!</string>
+ <string name="select_key_to_sign">Wybierz klucz, który zostanie użyty do podpisania!</string>
+ <string name="key_too_big_for_sharing">Klucz ma za duży rozmiar by być udostępniony w ten sposób!</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">usuwanie \'%s\' zakończone niepowodzeniem</string>
+ <string name="error_file_not_found">plik nie znaleziony</string>
+ <string name="error_no_secret_key_found">nie znaleziono pasującego klucza prywatnego</string>
+ <string name="error_no_known_encryption_found">napotkano nieznany rodzaj szyfrowania</string>
+ <string name="error_external_storage_not_ready">zewnętrzne urządzenie jest niegotowe</string>
+ <string name="error_invalid_email">nieprawidłowy adres email \'%s\'</string>
+ <string name="error_key_size_minimum512bit">klucz musi mieć rozmiar co najmniej 512 bitów</string>
+ <string name="error_master_key_must_not_be_el_gamal">klucz EnGamal nie może być kluczem głównym</string>
+ <string name="error_unknown_algorithm_choice">wybrano nieznany algorytm</string>
+ <string name="error_user_id_needs_a_name">musisz wskazać imię</string>
+ <string name="error_user_id_no_email">nie znaleziono adresu email</string>
+ <string name="error_user_id_needs_an_email_address">musisz wskazać adres email</string>
+ <string name="error_key_needs_a_user_id">potrzeba co najmniej jednego identyfikatora użytkownika</string>
+ <string name="error_main_user_id_must_not_be_empty">główny identyfikator użytkownika nie może być pusty</string>
+ <string name="error_key_needs_master_key">potrzeba co najmniej klucza głównego</string>
+ <string name="error_no_encryption_keys_or_passphrase">nie podano hasła ani klucza szyfrującego</string>
+ <string name="error_signature_failed">podpisywanie nie powiodło się</string>
+ <string name="error_no_signature_passphrase">nie podano hasła</string>
+ <string name="error_no_signature_key">nie podano klucza podpisu</string>
+ <string name="error_invalid_data">nieprawidłowe dane</string>
+ <string name="error_corrupt_data">uszkodzone dane</string>
+ <string name="error_integrity_check_failed">Sprawdzanie spójności zakończone niepowodzeniem! Dane były modyfikowane!</string>
+ <string name="error_no_symmetric_encryption_packet">nie znaleziono pakietu z szyfrowaniem symatrycznym</string>
+ <string name="error_wrong_passphrase">nieprawidłowe hasło</string>
+ <string name="error_saving_keys">błąd przy zapisywaniu kluczy</string>
+ <string name="error_could_not_extract_private_key">nie można wyodrębnić klucza prywatnego</string>
+ <string name="error_only_files_are_supported">Dane binarne pozbawione pliku nie są obsługiwane. To jest wspierane tylko dla akcji ACTION_ENCRYPT_STREAM_AND_RETURN.</string>
+ <string name="error_jelly_bean_needed">Potrzebujesz Androida 4.1 Jelly Bean, aby korzystać z Android NFC Beam!</string>
+ <string name="error_nfc_needed">NCF jest niedostępne na twoim urządzeniu</string>
+ <string name="error_nothing_import">Nie ma nic do zaimportowania!</string>
+ <string name="error_expiry_must_come_after_creation">data wygaśnięcia musi być późniejsza niż data stworzenia</string>
+ <string name="error_can_not_delete_contact">nie możesz usunąć tego kontaktu, ponieważ należy do ciebie.</string>
+ <string name="error_can_not_delete_contacts">nie możesz usunąć tych kontaktów, ponieważ należą do ciebie:\n%s</string>
+ <string name="error_keyserver_insufficient_query">Niewystarczające zapytanie do serwera</string>
+ <string name="error_keyserver_query">Odpytywanie serwera zakończone niepowodzeniem</string>
+ <string name="error_keyserver_too_many_responses">Za dużo odpowiedzi</string>
+ <string name="error_import_file_no_content">Plik jest pusty</string>
+ <string name="error_generic_report_bug">Wystąpił błąd ogólny, proszę zgłoś go autorom OpenKeychain.</string>
+ <plurals name="error_can_not_delete_info">
+ <item quantity="one">Usuń go z ekranu \'Moje klucze\'!</item>
+ <item quantity="few">Usuń je z ekranu \'Moje klucze\'!</item>
+ <item quantity="other">Usuń je z ekranu \'Moje klucze\'!</item>
+ </plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="one">Część wczytanego pliku jest poprawnym obiektem OpenPGP, ale nie jest kluczem OpenPGP</item>
+ <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>
+ <!--progress dialogs, usually ending in '…'-->
+ <string name="progress_done">Gotowe.</string>
+ <string name="progress_cancel">Anuluj</string>
+ <string name="progress_saving">zapisywanie...</string>
+ <string name="progress_importing">importowanie...</string>
+ <string name="progress_exporting">eksportowanie...</string>
+ <string name="progress_building_key">budowanie klucza...</string>
+ <string name="progress_preparing_master_key">przygotowywanie klucza glównego...</string>
+ <string name="progress_certifying_master_key">podpisywanie klucza głównego...</string>
+ <string name="progress_building_master_key">budowanie głównego zbioru kluczy...</string>
+ <string name="progress_adding_sub_keys">dodawanie podkluczy...</string>
+ <string name="progress_saving_key_ring">zapisywanie klucza...</string>
+ <plurals name="progress_exporting_key">
+ <item quantity="one">eksportowanie klucza...</item>
+ <item quantity="few">eksportowanie kluczy...</item>
+ <item quantity="other">eksportowanie kluczy...</item>
+ </plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">generowanie klucza, może to potrwać do 3 minut...</item>
+ <item quantity="few">generowanie kluczy, może to potrwać do 3 minut...</item>
+ <item quantity="other">generowanie kluczy, może to potrwać do 3 minut...</item>
+ </plurals>
+ <string name="progress_extracting_signature_key">wyodrębnianie klucza podpisu...</string>
+ <string name="progress_extracting_key">wyodrębnianie klucza...</string>
+ <string name="progress_preparing_streams">przygotowywanie strumieni...</string>
+ <string name="progress_encrypting">szyfrowanie danych...</string>
+ <string name="progress_decrypting">deszyfrowywanie danych...</string>
+ <string name="progress_preparing_signature">przygotowywanie podpisu...</string>
+ <string name="progress_generating_signature">generowanie podpisu...</string>
+ <string name="progress_processing_signature">przetwarzanie podpisu...</string>
+ <string name="progress_verifying_signature">weryfikowanie podpisu...</string>
+ <string name="progress_signing">podpisywanie...</string>
+ <string name="progress_reading_data">czytanie danych...</string>
+ <string name="progress_finding_key">szukanie klucza...</string>
+ <string name="progress_decompressing_data">dekompresja danych...</string>
+ <string name="progress_verifying_integrity">weryfikacja spójności...</string>
+ <string name="progress_deleting_securely">usuwanie \'%s\' bezpiecznie…</string>
+ <string name="progress_querying">odpytywanie...</string>
+ <!--action strings-->
+ <string name="hint_public_keys">Wyszukaj klucze publiczne</string>
+ <string name="hint_secret_keys">Wyszukaj klucze prywatne</string>
+ <string name="action_share_key_with">Udostępnij klucz...</string>
+ <!--key bit length selections-->
+ <string name="key_size_512">512</string>
+ <string name="key_size_1024">1024</string>
+ <string name="key_size_2048">2048</string>
+ <string name="key_size_4096">4096</string>
+ <!--compression-->
+ <string name="compression_fast">szybka</string>
+ <string name="compression_very_slow">bardzo wolna</string>
+ <!--Help-->
+ <string name="help_tab_start">Początek</string>
+ <string name="help_tab_faq">FAQ</string>
+ <string name="help_tab_nfc_beam">NFC Beam</string>
+ <string name="help_tab_changelog">Dziennik zmian</string>
+ <string name="help_tab_about">O programie</string>
+ <string name="help_about_version">Wersja:</string>
+ <!--Import-->
+ <string name="import_import">Zaimportuj wybrane klucze</string>
+ <string name="import_sign_and_upload">Importuj, podpisz i wyślij wybrane klucze</string>
+ <string name="import_from_clipboard">Importuj ze schowka</string>
+ <plurals name="import_qr_code_missing">
+ <item quantity="one">Brakuje kodu QR o identyfikatorze %s</item>
+ <item quantity="few">Brakuje kodów QR o identyfikatorach %s</item>
+ <item quantity="other">Brakuje kodów QR o identyfikatorach %s</item>
+ </plurals>
+ <string name="import_qr_code_start_with_one">Zacznij od kodu QR o identyfikatorze 1</string>
+ <string name="import_qr_code_wrong">Kod QR zniekształcony! Spróbuj jeszcze raz!</string>
+ <string name="import_qr_code_finished">Skanowanie kodu QR zakończone!</string>
+ <string name="import_qr_code_too_short_fingerprint">Odcisk klucza zawarty w tym kodzie QR jest za krótki (&lt; 16 znaków)</string>
+ <string name="import_qr_scan_button">Odczytaj kod QR przy pomocy \'Barcode Scanner\'</string>
+ <string name="import_nfc_text">Aby odbierać klucze przez NFC, urządzenie musi być odblokowane.</string>
+ <string name="import_nfc_help_button">Pomoc</string>
+ <string name="import_clipboard_button">Odczytaj klucz ze schowka</string>
+ <!--Intent labels-->
+ <string name="intent_decrypt_file">Deszyfruj plik korzystając z OpenKeychain</string>
+ <string name="intent_import_key">Importuj klucz korzystając z OpenKeychain</string>
+ <string name="intent_send_encrypt">Zaszyfruj korzystając z OpenKeychain</string>
+ <string name="intent_send_decrypt">Deszyfruj korzystając z OpenKeychain</string>
+ <!--Remote API-->
+ <string name="api_no_apps">Brak zarejestrowanych aplikacji!\n\nZewnętrzne aplikacje mogą żądać dostępu do OpenKeychain. Po przyznaniu dostępu, będa wyświetlone tutaj.</string>
+ <string name="api_settings_show_info">Pokaż zaawansowane informacje</string>
+ <string name="api_settings_hide_info">Ukryj zaawansowane informacje</string>
+ <string name="api_settings_show_advanced">Pokaż zaawanowane ustawienia</string>
+ <string name="api_settings_hide_advanced">Ukryj zaawansowane ustawienia</string>
+ <string name="api_settings_no_key">Nie wybrano klucza</string>
+ <string name="api_settings_select_key">Wybierz klucz</string>
+ <string name="api_settings_save">Zapisz</string>
+ <string name="api_settings_cancel">Anuluj</string>
+ <string name="api_settings_revoke">Odwołaj dostęp</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_accounts">Konta</string>
+ <string name="api_settings_accounts_empty">Nie przypisano żadnych kont do tej aplikacji</string>
+ <string name="api_register_text">Wyświetlona aplikacja prosi o dostęp do OpenKeychain.\nZezwolić?\n\nOSTRZEZENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezwalaj na dostęp! Możesz to również zrobić później, korzystając z ekranu \'Zarejestrowane aplikacje\'.</string>
+ <string name="api_register_allow">Zezwól na dostęp</string>
+ <string name="api_register_disallow">Odmów dostępu</string>
+ <string name="api_register_error_select_key">Wybierz klucz!</string>
+ <string name="api_select_pub_keys_missing_text">Nie znaleziono kluczy publiczych dla tych identyfikatorów użytkownika:</string>
+ <string name="api_select_pub_keys_dublicates_text">Więcej niż jeden klucz publiczny istnieje dla tych identyfikatorów użytkownika:</string>
+ <string name="api_select_pub_keys_text">Proszę przejrzeć listę adresatów!</string>
+ <string name="api_error_wrong_signature">Sprawdzanie podpisu zakończone niepowodzeniem! Czy zainstalowałeś tę aplikację z innego źródła? Jeżeli jesteś pewien, że nie jest to atak, odwołaj rejestrację teg aplikacji w OpenKeychain, a następnie zarejestruj ją ponownie.</string>
+ <!--Share-->
+ <string name="share_qr_code_dialog_title">Udostępnij przez kod QR</string>
+ <string name="share_qr_code_dialog_start">Przejdź przez wszystkiego kody QR korzystając z przycisku \'Nastepny\' i skanuj je pojedynczo.</string>
+ <string name="share_qr_code_dialog_fingerprint_text">Odcisk:</string>
+ <string name="share_qr_code_dialog_progress">Kod QR o identyfikatorze %1$d z %2$d</string>
+ <string name="share_nfc_dialog">Udostępnij przez NFC</string>
+ <!--Key list-->
+ <plurals name="key_list_selected_keys">
+ <item quantity="one">1 klucz wybrany.</item>
+ <item quantity="few">%d kluczy wybranych.</item>
+ <item quantity="other">%d kluczy wybranych.</item>
+ </plurals>
+ <string name="key_list_empty_text1">Żadne klucze nie są jeszcze dostępne...</string>
+ <string name="key_list_empty_text2">Możesz zacząć od</string>
+ <string name="key_list_empty_text3">lub</string>
+ <string name="key_list_empty_button_create">tworzenie własnego klucza</string>
+ <string name="key_list_empty_button_import">importowanie kluczy.</string>
+ <!--Key view-->
+ <string name="key_view_action_edit">Edytuj ten klucz</string>
+ <string name="key_view_action_encrypt">Zaszyfruj do tego kontaktu</string>
+ <string name="key_view_action_certify">Certyfikuj klucz tego kontaktu</string>
+ <string name="key_view_tab_main">Informacje</string>
+ <string name="key_view_tab_certs">Certyfikaty</string>
+ <!--Navigation Drawer-->
+ <string name="nav_contacts">Kontakty</string>
+ <string name="nav_encrypt">Zaszyfruj</string>
+ <string name="nav_decrypt">Deszyfruj</string>
+ <string name="nav_import">importuj klucze</string>
+ <string name="nav_secret_keys">Moje klucze</string>
+ <string name="nav_apps">Zarejestrowane aplikacje</string>
+ <string name="drawer_open">Otwórz panel nawigacji</string>
+ <string name="drawer_close">Zamknij panel nawigacji</string>
+ <string name="edit">Edytuj</string>
+ <string name="my_keys">Moje klucze</string>
+ <string name="label_secret_key">Klucz prywatny</string>
+ <string name="secret_key_yes">dostępny</string>
+ <string name="secret_key_no">niedostepny</string>
+ <string name="section_uids_to_sign">Identyfikator użytkownika do podpisu</string>
+ <string name="progress_re_adding_certs">Ponowne stosowanie certyfikatów</string>
+ <!--hints-->
+ <string name="encrypt_content_edit_text_hint">Wpisz tutaj wiadomość do zaszyfrowania...</string>
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-pt-rBR/strings.xml b/OpenPGP-Keychain/src/main/res/values-pt-rBR/strings.xml
index 6bb115049..3d00a143f 100644
--- a/OpenPGP-Keychain/src/main/res/values-pt-rBR/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-pt-rBR/strings.xml
@@ -23,4 +23,5 @@
<!--Key list-->
<!--Key view-->
<!--Navigation Drawer-->
+ <!--hints-->
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-ru/strings.xml b/OpenPGP-Keychain/src/main/res/values-ru/strings.xml
index f69cf8789..88a529b66 100644
--- a/OpenPGP-Keychain/src/main/res/values-ru/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-ru/strings.xml
@@ -15,7 +15,8 @@
<string name="title_key_server_preference">Настройки сервера ключей</string>
<string name="title_change_passphrase">Изменить пароль</string>
<string name="title_set_passphrase">Задать пароль</string>
- <string name="title_send_email">Отправить…</string>
+ <string name="title_send_email">Отправить...</string>
+ <string name="title_send_file">Отправить файл</string>
<string name="title_encrypt_to_file">Зашифровать в файл</string>
<string name="title_decrypt_to_file">Расшифровать в файл</string>
<string name="title_import_keys">Импорт ключей</string>
@@ -61,8 +62,10 @@
<string name="btn_next">Далее</string>
<string name="btn_back">Назад</string>
<string name="btn_clipboard">Буфер обмена</string>
- <string name="btn_share">Поделиться…</string>
+ <string name="btn_share">Поделиться...</string>
<string name="btn_lookup_key">Найти ключ</string>
+ <string name="btn_encryption_advanced_settings_show">Показать расширенные настройки</string>
+ <string name="btn_encryption_advanced_settings_hide">Скрыть расширенные настройки</string>
<!--menu-->
<string name="menu_preferences">Настройки</string>
<string name="menu_help">Помощь</string>
@@ -71,17 +74,19 @@
<string name="menu_import">Импорт</string>
<string name="menu_import_from_nfc">Импорт из NFC</string>
<string name="menu_export_keys">Экспорт всех ключей</string>
+ <string name="menu_export_secret_keys">Экспорт всех секретных ключей</string>
<string name="menu_export_key">Экспорт в файл</string>
<string name="menu_delete_key">Удалить ключ</string>
<string name="menu_create_key">Создать ключ</string>
<string name="menu_create_key_expert">Создать ключ (эксперт)</string>
<string name="menu_search">Поиск</string>
- <string name="menu_key_server">Импорт с сервера ключей</string>
+ <string name="menu_import_from_key_server">Сервер ключей</string>
+ <string name="menu_key_server">Сервер ключей...</string>
<string name="menu_update_key">Обновить с сервера ключей</string>
<string name="menu_export_key_to_server">Загрузить на сервер ключей</string>
- <string name="menu_share">Отправить…</string>
- <string name="menu_share_title_fingerprint">Отправить отпечаток…</string>
- <string name="menu_share_title">Отправить ключ…</string>
+ <string name="menu_share">Отправить...</string>
+ <string name="menu_share_title_fingerprint">Отправить отпечаток...</string>
+ <string name="menu_share_title">Отправить ключ...</string>
<string name="menu_share_default_fingerprint">Отправить</string>
<string name="menu_share_default">Отправить</string>
<string name="menu_share_qr_code">QR код</string>
@@ -91,7 +96,8 @@
<string name="menu_sign_key">Подписать ключ</string>
<string name="menu_beam_preferences">Настройки Beam</string>
<string name="menu_key_edit_cancel">Отмена</string>
- <string name="menu_encrypt_to">Зашифровать….</string>
+ <string name="menu_encrypt_to">Зашифровать....</string>
+ <string name="menu_select_all">Выбрать все</string>
<!--label-->
<string name="label_sign">Подписать</string>
<string name="label_message">Сообщение</string>
@@ -104,6 +110,7 @@
<string name="label_select_public_keys">Получатели</string>
<string name="label_delete_after_encryption">Удалить после шифрования</string>
<string name="label_delete_after_decryption">Удалить после расшифровки</string>
+ <string name="label_share_after_encryption">Отправить после шифрования</string>
<string name="label_encryption_algorithm">Алгоритм шифрования</string>
<string name="label_hash_algorithm">Hash-алгоритм</string>
<string name="label_asymmetric">Публичный ключ</string>
@@ -115,7 +122,7 @@
<string name="label_key_servers">Серверы ключей</string>
<string name="label_key_id">ID ключа</string>
<string name="label_creation">Создан</string>
- <string name="label_expiry">Годен до…</string>
+ <string name="label_expiry">Годен до...</string>
<string name="label_usage">Применение</string>
<string name="label_key_size">Размер ключа</string>
<string name="label_main_user_id">Основной ID пользователя</string>
@@ -125,6 +132,7 @@
<string name="label_send_key">После сертификации загрузить ключ на сервер</string>
<string name="label_fingerprint">Отпечаток</string>
<string name="select_keys_button_default">Выбрать</string>
+ <string name="expiry_date_dialog_title">Срок годности</string>
<plurals name="select_keys_button">
<item quantity="one">%d выбран</item>
<item quantity="few">%d выбрано</item>
@@ -133,11 +141,18 @@
<string name="user_id_no_name">&lt;нет имени&gt;</string>
<string name="none">&lt;нет&gt;</string>
<string name="no_key">&lt;нет ключа&gt;</string>
+ <string name="no_email">&lt;нет email&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">шифрование</string>
<string name="can_sign">подпись</string>
<string name="expired">просрочен</string>
<string name="revoked">отозван</string>
+ <string name="user_id">ID пользователя</string>
+ <plurals name="n_contacts">
+ <item quantity="one">1 контакт</item>
+ <item quantity="few">%d контактов</item>
+ <item quantity="other">%d контактов</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="one">%d сервер ключей</item>
<item quantity="few">%d серверов ключей</item>
@@ -165,7 +180,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">Открыть…</string>
+ <string name="filemanager_title_open">Открыть...</string>
<string name="warning">Внимание</string>
<string name="error">Ошибка</string>
<string name="error_message">Ошибка: %s</string>
@@ -194,6 +209,9 @@
<string name="key_deletion_confirmation">Вы уверены, что ходите удалить ключ \'%s\'?\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>
+ <string name="secret_key_delete_text">Удалить секретные ключи?</string>
+ <string name="also_export_secret_keys">Экспортировать секретные ключи?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">Успешно добавлено %d ключ</item>
<item quantity="few">Успешно добавлено %d ключей</item>
@@ -219,6 +237,7 @@
<string name="keys_exported">Экспортировано %d ключей.</string>
<string name="no_keys_exported">Ключи не были экспортированы.</string>
<string name="key_creation_el_gamal_info">Инфо: ElGamal подходит только для дополнительных ключей. При создании ключа будет использован ближайший из размеров: 1536, 2048, 3072, 4096, или 8192.</string>
+ <string name="key_creation_weak_rsa_info">Внимание: создание ключей RSA длиной 1024 бита и менее признано небезопасным. Данная возможность отключена.</string>
<string name="key_not_found">Не удается найти ключ %08X.</string>
<plurals name="keys_found">
<item quantity="one">Найден %d ключ.</item>
@@ -252,6 +271,7 @@
<string name="error_master_key_must_not_be_el_gamal">ключ ElGamal не может быть основным</string>
<string name="error_unknown_algorithm_choice">выбран неизвестный алгоритм</string>
<string name="error_user_id_needs_a_name">необходимо указать имя</string>
+ <string name="error_user_id_no_email">email не найден</string>
<string name="error_user_id_needs_an_email_address">необходимо указать email</string>
<string name="error_key_needs_a_user_id">необходим хотя бы один id пользователя</string>
<string name="error_main_user_id_must_not_be_empty">основная запись пользователя не может быть пустой</string>
@@ -277,48 +297,60 @@
<string name="error_keyserver_insufficient_query">Ограничение запроса сервера</string>
<string name="error_keyserver_query">Сбой запроса сервера ключей</string>
<string name="error_keyserver_too_many_responses">Слишком много ответов</string>
+ <string name="error_import_file_no_content">Файл пуст</string>
+ <string name="error_generic_report_bug">Выявлена ошибка. Пожалуйста, сообщите о ней разработчику.</string>
<plurals name="error_can_not_delete_info">
<item quantity="one">Пожалуйста, удалите его в разделе \'Мои ключи\'!</item>
<item quantity="few">Пожалуйста, удалите их в разделе \'Мои ключи\'!</item>
<item quantity="other">Пожалуйста, удалите их в разделе \'Мои ключи\'!</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="one">часть загруженного файла содержит данные OpenPGP, но это не ключ</item>
+ <item quantity="few">части загруженного файла содержат данные OpenPGP, но это не ключ</item>
+ <item quantity="other">части загруженного файла содержат данные OpenPGP, но это не ключ</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">готово.</string>
- <string name="progress_saving">сохранение…</string>
- <string name="progress_importing">импорт…</string>
- <string name="progress_exporting">экспорт…</string>
- <string name="progress_generating">создание ключа. это может занять до 3 минут…</string>
- <string name="progress_building_key">создание ключа…</string>
- <string name="progress_preparing_master_key">подготовка основного ключа…</string>
- <string name="progress_certifying_master_key">сертификация основного ключа…</string>
- <string name="progress_building_master_key">создание основной связки…</string>
- <string name="progress_adding_sub_keys">добавление доп. ключей…</string>
- <string name="progress_saving_key_ring">сохранение ключа…</string>
+ <string name="progress_done">Готово.</string>
+ <string name="progress_cancel">Отмена</string>
+ <string name="progress_saving">сохранение...</string>
+ <string name="progress_importing">импорт...</string>
+ <string name="progress_exporting">экспорт...</string>
+ <string name="progress_building_key">создание ключа...</string>
+ <string name="progress_preparing_master_key">подготовка основного ключа...</string>
+ <string name="progress_certifying_master_key">сертификация основного ключа...</string>
+ <string name="progress_building_master_key">создание основной связки...</string>
+ <string name="progress_adding_sub_keys">добавление доп. ключей...</string>
+ <string name="progress_saving_key_ring">сохранение ключа...</string>
<plurals name="progress_exporting_key">
- <item quantity="one">экспорт ключа…</item>
- <item quantity="few">экспорт ключей…</item>
- <item quantity="other">экспорт ключей…</item>
+ <item quantity="one">экспорт ключа...</item>
+ <item quantity="few">экспорт ключей...</item>
+ <item quantity="other">экспорт ключей...</item>
+ </plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">создание ключа. это может занять до 3 минут...</item>
+ <item quantity="few">создание ключей. это может занять до 3 минут...</item>
+ <item quantity="other">создание ключей. это может занять до 3 минут...</item>
</plurals>
- <string name="progress_extracting_signature_key">извлечение подписи ключа…</string>
- <string name="progress_extracting_key">извлечение ключа…</string>
- <string name="progress_preparing_streams">подготовка к передаче…</string>
- <string name="progress_encrypting">шифрование данных…</string>
- <string name="progress_decrypting">расшифровка данных…</string>
- <string name="progress_preparing_signature">подготовка подписи…</string>
- <string name="progress_generating_signature">формирование подписи…</string>
- <string name="progress_processing_signature">обработка подписи…</string>
- <string name="progress_verifying_signature">проверка подписи…</string>
- <string name="progress_signing">подписание…</string>
- <string name="progress_reading_data">чтение данных…</string>
- <string name="progress_finding_key">поиск ключа…</string>
- <string name="progress_decompressing_data">распаковка данных…</string>
- <string name="progress_verifying_integrity">проверка целостности…</string>
- <string name="progress_deleting_securely">безопасное удаление \'%s\'…</string>
- <string name="progress_querying">запрос…</string>
+ <string name="progress_extracting_signature_key">извлечение подписи ключа...</string>
+ <string name="progress_extracting_key">извлечение ключа...</string>
+ <string name="progress_preparing_streams">подготовка к передаче...</string>
+ <string name="progress_encrypting">шифрование данных...</string>
+ <string name="progress_decrypting">расшифровка данных...</string>
+ <string name="progress_preparing_signature">подготовка подписи...</string>
+ <string name="progress_generating_signature">формирование подписи...</string>
+ <string name="progress_processing_signature">обработка подписи...</string>
+ <string name="progress_verifying_signature">проверка подписи...</string>
+ <string name="progress_signing">подписание...</string>
+ <string name="progress_reading_data">чтение данных...</string>
+ <string name="progress_finding_key">поиск ключа...</string>
+ <string name="progress_decompressing_data">распаковка данных...</string>
+ <string name="progress_verifying_integrity">проверка целостности...</string>
+ <string name="progress_deleting_securely">безопасное удаление \'%s\'...</string>
+ <string name="progress_querying">запрос...</string>
<!--action strings-->
<string name="hint_public_keys">Найти публичные ключи</string>
<string name="hint_secret_keys">Найти секретные ключи</string>
- <string name="action_share_key_with">Отправить…</string>
+ <string name="action_share_key_with">Отправить...</string>
<!--key bit length selections-->
<string name="key_size_512">512</string>
<string name="key_size_1024">1024</string>
@@ -329,6 +361,7 @@
<string name="compression_very_slow">очень медленно</string>
<!--Help-->
<string name="help_tab_start">Начать</string>
+ <string name="help_tab_faq">ЧаВо</string>
<string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Изменения</string>
<string name="help_tab_about">О программе</string>
@@ -386,12 +419,13 @@
<item quantity="few">%d ключей выбрано.</item>
<item quantity="other">%d ключей выбрано.</item>
</plurals>
- <string name="key_list_empty_text1">У вас пока нет ключей…</string>
+ <string name="key_list_empty_text1">У вас пока нет ключей...</string>
<string name="key_list_empty_text2">Но Вы можете</string>
<string name="key_list_empty_text3">или</string>
<string name="key_list_empty_button_create">создать свой ключ</string>
<string name="key_list_empty_button_import">Импортировать ключи</string>
<!--Key view-->
+ <string name="key_view_action_edit">Изменить ключ</string>
<string name="key_view_action_encrypt">Зашифровать для этого получателя</string>
<string name="key_view_action_certify">Сертифицировать ключ этого контакта</string>
<string name="key_view_tab_main">Информация</string>
@@ -405,4 +439,11 @@
<string name="nav_apps">Связанные приложения</string>
<string name="drawer_open">Открыть панель навигации</string>
<string name="drawer_close">Закрыть панель навигации</string>
+ <string name="edit">Изменить</string>
+ <string name="my_keys">Мои ключи</string>
+ <string name="label_secret_key">Секретный ключ</string>
+ <string name="secret_key_yes">доступен</string>
+ <string name="secret_key_no">не доступен</string>
+ <!--hints-->
+ <string name="encrypt_content_edit_text_hint">Напишите сообщение здесь, что бы зашифровать...</string>
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-sl-rSI/strings.xml b/OpenPGP-Keychain/src/main/res/values-sl-rSI/strings.xml
index 6bb115049..3d00a143f 100644
--- a/OpenPGP-Keychain/src/main/res/values-sl-rSI/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-sl-rSI/strings.xml
@@ -23,4 +23,5 @@
<!--Key list-->
<!--Key view-->
<!--Navigation Drawer-->
+ <!--hints-->
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-tr/strings.xml b/OpenPGP-Keychain/src/main/res/values-tr/strings.xml
index 4f1becaa1..174d8538f 100644
--- a/OpenPGP-Keychain/src/main/res/values-tr/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-tr/strings.xml
@@ -76,7 +76,7 @@
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="filemanager_title_open">Aç…</string>
+ <string name="filemanager_title_open">Aç...</string>
<string name="warning">Uyarı</string>
<string name="error">Hata</string>
<string name="error_message">Hata: %s</string>
@@ -95,18 +95,17 @@
<string name="error_key_size_minimum512bit">anahtar uzunluğu en az 512bit olmalı</string>
<string name="error_corrupt_data">bozuk veri</string>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">bitti.</string>
- <string name="progress_saving">kaydediliyor…</string>
- <string name="progress_importing">alıyor…</string>
- <string name="progress_exporting">veriyor…</string>
- <string name="progress_building_key">anahtar oluşturuluyor…</string>
- <string name="progress_preparing_signature">imza hazırlanıyor…</string>
- <string name="progress_generating_signature">imza oluşturuluyor…</string>
- <string name="progress_processing_signature">imza işleniyor…</string>
- <string name="progress_verifying_signature">imza doğrulanıyor…</string>
- <string name="progress_signing">imzalanıyor…</string>
- <string name="progress_reading_data">veri okunuyor…</string>
- <string name="progress_finding_key">anahtar bulunuyor…</string>
+ <string name="progress_saving">kaydediliyor...</string>
+ <string name="progress_importing">alıyor...</string>
+ <string name="progress_exporting">veriyor...</string>
+ <string name="progress_building_key">anahtar oluşturuluyor...</string>
+ <string name="progress_preparing_signature">imza hazırlanıyor...</string>
+ <string name="progress_generating_signature">imza oluşturuluyor...</string>
+ <string name="progress_processing_signature">imza işleniyor...</string>
+ <string name="progress_verifying_signature">imza doğrulanıyor...</string>
+ <string name="progress_signing">imzalanıyor...</string>
+ <string name="progress_reading_data">veri okunuyor...</string>
+ <string name="progress_finding_key">anahtar bulunuyor...</string>
<!--action strings-->
<!--key bit length selections-->
<string name="key_size_512">512</string>
@@ -135,4 +134,5 @@
<!--Key list-->
<!--Key view-->
<!--Navigation Drawer-->
+ <!--hints-->
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-uk/strings.xml b/OpenPGP-Keychain/src/main/res/values-uk/strings.xml
index 8997ef5ce..00655fc53 100644
--- a/OpenPGP-Keychain/src/main/res/values-uk/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-uk/strings.xml
@@ -16,6 +16,7 @@
<string name="title_change_passphrase">Змінити парольну фразу</string>
<string name="title_set_passphrase">Задати парольну фразу</string>
<string name="title_send_email">Надіслати листа…</string>
+ <string name="title_send_file">Надіслати файл…</string>
<string name="title_encrypt_to_file">Зашифрувати до файлу</string>
<string name="title_decrypt_to_file">Розшифрувати до файлу</string>
<string name="title_import_keys">Імпортувати ключі</string>
@@ -63,6 +64,8 @@
<string name="btn_clipboard">Буфер обміну</string>
<string name="btn_share">Поділитися через…</string>
<string name="btn_lookup_key">Шукати ключ</string>
+ <string name="btn_encryption_advanced_settings_show">Показати додаткові налаштування</string>
+ <string name="btn_encryption_advanced_settings_hide">Приховати додаткові налаштування</string>
<!--menu-->
<string name="menu_preferences">Параметри</string>
<string name="menu_help">Довідка</string>
@@ -71,15 +74,17 @@
<string name="menu_import">Імпорт</string>
<string name="menu_import_from_nfc">Імпорт з NFC</string>
<string name="menu_export_keys">Експортувати усі ключі</string>
+ <string name="menu_export_secret_keys">Експортувати усі секретні ключі</string>
<string name="menu_export_key">Експорт до файлу</string>
<string name="menu_delete_key">Вилучити ключ</string>
<string name="menu_create_key">Створити ключ</string>
<string name="menu_create_key_expert">Створити ключ (експерт)</string>
<string name="menu_search">Пошук</string>
- <string name="menu_key_server">Імпорт з сервера ключів</string>
+ <string name="menu_import_from_key_server">Сервер ключів</string>
+ <string name="menu_key_server">Сервер ключів…</string>
<string name="menu_update_key">Оновити з сервера ключів</string>
<string name="menu_export_key_to_server">Завантажити на сервер ключів</string>
- <string name="menu_share">Поділитися</string>
+ <string name="menu_share">Поділитися…</string>
<string name="menu_share_title_fingerprint">Поділитися відбитком…</string>
<string name="menu_share_title">Поділитися цілим ключем…</string>
<string name="menu_share_default_fingerprint">з…</string>
@@ -92,6 +97,7 @@
<string name="menu_beam_preferences">Налаштування променя</string>
<string name="menu_key_edit_cancel">Скасувати</string>
<string name="menu_encrypt_to">Зашифрувати…</string>
+ <string name="menu_select_all">Вибрати усе</string>
<!--label-->
<string name="label_sign">Підпис</string>
<string name="label_message">Повідомлення</string>
@@ -104,6 +110,7 @@
<string name="label_select_public_keys">Отримувачі</string>
<string name="label_delete_after_encryption">Вилучити після шифрування</string>
<string name="label_delete_after_decryption">Вилучити після розшифрування</string>
+ <string name="label_share_after_encryption">Поширити після шифрування</string>
<string name="label_encryption_algorithm">Алгоритм шифрування</string>
<string name="label_hash_algorithm">Хеш алгоритм</string>
<string name="label_asymmetric">Публічний ключ</string>
@@ -122,9 +129,12 @@
<string name="label_name">Назва</string>
<string name="label_comment">Коментар</string>
<string name="label_email">Ел. пошта</string>
+ <string name="label_sign_user_id">Ід підпису користувача</string>
+ <string name="label_sign_email">Підписати листа</string>
<string name="label_send_key">Завантажити ключ до вибраного сервера ключів після сертифікації</string>
<string name="label_fingerprint">Відбиток</string>
<string name="select_keys_button_default">Вибрати</string>
+ <string name="expiry_date_dialog_title">Задати термін дії</string>
<plurals name="select_keys_button">
<item quantity="one">%d вибраний</item>
<item quantity="few">%d вибрані</item>
@@ -133,11 +143,18 @@
<string name="user_id_no_name">&lt;без імені&gt;</string>
<string name="none">&lt;жоден&gt;</string>
<string name="no_key">&lt;без ключа&gt;</string>
+ <string name="no_email">&lt;Немає ел. пошти&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">можна зашифрувати</string>
<string name="can_sign">можна підписати</string>
<string name="expired">закінчився</string>
<string name="revoked">скасовано</string>
+ <string name="user_id">ІД користувача</string>
+ <plurals name="n_contacts">
+ <item quantity="one">1 контакт</item>
+ <item quantity="few">%d контакти</item>
+ <item quantity="other">%d контактів</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="one">%d сервер ключів</item>
<item quantity="few">%d сервери ключів</item>
@@ -194,6 +211,9 @@
<string name="key_deletion_confirmation">Ви справді хочете вилучити ключ \'%s\'?\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>
+ <string name="secret_key_delete_text">Видалити секретні ключі?</string>
+ <string name="also_export_secret_keys">Також експортувати секретні ключі?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">Успішно додано %d ключ</item>
<item quantity="few">Успішно додано %d ключі</item>
@@ -219,6 +239,7 @@
<string name="keys_exported">Успішно експортовано %d ключів.</string>
<string name="no_keys_exported">Жодного ключа не експортовано.</string>
<string name="key_creation_el_gamal_info">Примітка: тільки підключі підтримують ElGamal, а для ElGamal буде використаний найближчий розмір ключа з 1536, 2048, 3072, 4096, або 8192.</string>
+ <string name="key_creation_weak_rsa_info">Примітка: генерація ключа RSA з довжиною 1024 біти і менше вважається небезпечною і вона вимкнена для генерації нових ключів.</string>
<string name="key_not_found">Не можливо знайти ключ %08X.</string>
<plurals name="keys_found">
<item quantity="one">Знайдено %d ключ.</item>
@@ -252,6 +273,7 @@
<string name="error_master_key_must_not_be_el_gamal">основний ключ не може бути ключем ElGamal</string>
<string name="error_unknown_algorithm_choice">вибір невідомого алгоритму</string>
<string name="error_user_id_needs_a_name">вам потрібно вказати назву</string>
+ <string name="error_user_id_no_email">жодного листа не знайдено</string>
<string name="error_user_id_needs_an_email_address">вам потрібно вказати електронну адресу</string>
<string name="error_key_needs_a_user_id">потрібний хоча б один ІД користувача</string>
<string name="error_main_user_id_must_not_be_empty">ІД основного користувача не має бути порожнім</string>
@@ -277,17 +299,24 @@
<string name="error_keyserver_insufficient_query">Запит обмеженого сервера</string>
<string name="error_keyserver_query">Збій сервера ключа запиту</string>
<string name="error_keyserver_too_many_responses">Забагато відповідей</string>
+ <string name="error_import_file_no_content">Файл не має вмісту</string>
+ <string name="error_generic_report_bug">Трапилася загальна помилка, будь ласка, створіть новий звіт про помилку для OpenKeychain.</string>
<plurals name="error_can_not_delete_info">
<item quantity="one">Будь ласка, вилучіть його з екрану „Мої ключі“!</item>
<item quantity="few">Будь ласка, вилучіть їх з екрану „Мої ключі“!</item>
<item quantity="other">Будь ласка, вилучіть їх з екрану „Мої ключі“!</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="one">частина завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
+ <item quantity="few">частини завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
+ <item quantity="other">частин завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
+ </plurals>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">готово.</string>
+ <string name="progress_done">Готово.</string>
+ <string name="progress_cancel">Скасувати</string>
<string name="progress_saving">збереження…</string>
<string name="progress_importing">імпортується…</string>
<string name="progress_exporting">експортується…</string>
- <string name="progress_generating">генерується ключ, вона може тривати до 3 хвилин…</string>
<string name="progress_building_key">будується ключ…</string>
<string name="progress_preparing_master_key">підготовка основного ключа…</string>
<string name="progress_certifying_master_key">сертифікація основного ключа…</string>
@@ -299,6 +328,11 @@
<item quantity="few">експортуються ключі…</item>
<item quantity="other">експортуються ключі…</item>
</plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">генерується ключ, це може тривати до 3 хвилини</item>
+ <item quantity="few">генеруються ключі, це може тривати до 3 хвилини</item>
+ <item quantity="other">генеруються ключі, це може тривати до 3 хвилини</item>
+ </plurals>
<string name="progress_extracting_signature_key">видобування ключа підпису…</string>
<string name="progress_extracting_key">видобувається ключа…</string>
<string name="progress_preparing_streams">підготовка потоків…</string>
@@ -329,6 +363,7 @@
<string name="compression_very_slow">дуже повільне</string>
<!--Help-->
<string name="help_tab_start">Початок</string>
+ <string name="help_tab_faq">ЧАП</string>
<string name="help_tab_nfc_beam">NFC промінь</string>
<string name="help_tab_changelog">Журнал змін</string>
<string name="help_tab_about">Про</string>
@@ -357,6 +392,8 @@
<string name="intent_send_decrypt">Розшифрувати з OpenKeychain</string>
<!--Remote API-->
<string name="api_no_apps">Нема зареєстрованих програм!\n\nСтороні програми можуть вимагати доступ до OpenPGP Keychain. Після надання доступу вони будуть наведені тут.</string>
+ <string name="api_settings_show_info">Показати додаткову інформацію</string>
+ <string name="api_settings_hide_info">Приховати додаткову інформацію</string>
<string name="api_settings_show_advanced">Показати додаткові налаштування</string>
<string name="api_settings_hide_advanced">Приховати додаткові налаштування</string>
<string name="api_settings_no_key">Не вибрано ключа</string>
@@ -366,6 +403,8 @@
<string name="api_settings_revoke">Відкликати доступ</string>
<string name="api_settings_package_name">Назва пакунку</string>
<string name="api_settings_package_signature">SHA-256 підписку пакунку</string>
+ <string name="api_settings_accounts">Облікові записи</string>
+ <string name="api_settings_accounts_empty">Немає облікового запису приєднаного до цієї програми.</string>
<string name="api_register_text">Показана програма запитує доступ до OpenPGP Keychain.\nДозволити доступ?\n\nУВАГА: якщо ви не знаєте, чому цей екран появився, не дозволяйте доступ! Ви можете відкликати доступ пізніше, використовуючи екран \'Зареєстровані програми\'.</string>
<string name="api_register_allow">Дозволити доступ</string>
<string name="api_register_disallow">Не дозволити доступ</string>
@@ -392,6 +431,7 @@
<string name="key_list_empty_button_create">створюється ваш власний ключ</string>
<string name="key_list_empty_button_import">імпортуюся ключі.</string>
<!--Key view-->
+ <string name="key_view_action_edit">Редагувати цей ключ</string>
<string name="key_view_action_encrypt">Зашифрувати у цей контакт</string>
<string name="key_view_action_certify">Сертифікувати ключ цього контакту</string>
<string name="key_view_tab_main">Інформація</string>
@@ -405,4 +445,13 @@
<string name="nav_apps">Зареєстровані програми</string>
<string name="drawer_open">Відкрити панель навігації</string>
<string name="drawer_close">Закрити панель навігації</string>
+ <string name="edit">Редагувати</string>
+ <string name="my_keys">Мої ключі</string>
+ <string name="label_secret_key">Секретний ключ</string>
+ <string name="secret_key_yes">доступний</string>
+ <string name="secret_key_no">недоступний</string>
+ <string name="section_uids_to_sign">ІД користувача для реєстрації</string>
+ <string name="progress_re_adding_certs">Перезастосування сертифікатів</string>
+ <!--hints-->
+ <string name="encrypt_content_edit_text_hint">Напишіть повідомлення для шифрування…</string>
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-zh-rTW/strings.xml b/OpenPGP-Keychain/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000..3d00a143f
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,27 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <!--title-->
+ <!--section-->
+ <!--button-->
+ <!--menu-->
+ <!--label-->
+ <string name="unknown_status"></string>
+ <!--choice-->
+ <!--sentences-->
+ <!--errors
+ no punctuation, all lowercase,
+ they will be put after "error_message", e.g. "Error: file not found"-->
+ <!--progress dialogs, usually ending in '…'-->
+ <!--action strings-->
+ <!--key bit length selections-->
+ <!--compression-->
+ <!--Help-->
+ <!--Import-->
+ <!--Intent labels-->
+ <!--Remote API-->
+ <!--Share-->
+ <!--Key list-->
+ <!--Key view-->
+ <!--Navigation Drawer-->
+ <!--hints-->
+</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values-zh/strings.xml b/OpenPGP-Keychain/src/main/res/values-zh/strings.xml
index 5848fb8db..244e7e57b 100644
--- a/OpenPGP-Keychain/src/main/res/values-zh/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values-zh/strings.xml
@@ -1,17 +1,48 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<!--title-->
+ <string name="title_manage_public_keys">聯絡人</string>
+ <string name="title_select_recipients">选择公钥</string>
+ <string name="title_select_secret_key">选择私钥</string>
<string name="title_encrypt">加密</string>
<string name="title_decrypt">解密</string>
+ <string name="title_authentication">密码短语</string>
+ <string name="title_create_key">创建密钥</string>
+ <string name="title_edit_key">编辑密钥</string>
+ <string name="title_preferences">参数</string>
+ <string name="title_api_registered_apps">已注册应用</string>
<string name="title_key_server_preference">密钥服务器偏好</string>
+ <string name="title_set_passphrase">设置密码短语</string>
+ <string name="title_send_email">发送邮件</string>
+ <string name="title_encrypt_to_file">加密至文件</string>
+ <string name="title_decrypt_to_file">解密至文件</string>
+ <string name="title_import_keys">导入密钥</string>
+ <string name="title_export_key">导出密钥</string>
+ <string name="title_export_keys">导出密钥</string>
+ <string name="title_key_not_found">无法找到密钥</string>
<string name="title_key_server_query">查询密钥服务器</string>
<string name="title_send_key">上传到密钥服务器</string>
+ <string name="title_unknown_signature_key">未知签名密钥</string>
+ <string name="title_help">帮助</string>
<!--section-->
+ <string name="section_user_ids">用户ID</string>
+ <string name="section_keys">密钥</string>
+ <string name="section_general">常规</string>
+ <string name="section_defaults">缺省</string>
+ <string name="section_advanced">高级</string>
<string name="section_master_key">主密钥</string>
<string name="section_key_server">密钥服务器</string>
<string name="section_decrypt_verify">解密并验证</string>
<!--button-->
+ <string name="btn_sign">签名</string>
+ <string name="btn_decrypt">解密</string>
<string name="btn_decrypt_verify">解密并验证</string>
+ <string name="btn_select_encrypt_keys">选择收件人</string>
+ <string name="btn_encrypt_file">加密文件</string>
+ <string name="btn_save">保存</string>
+ <string name="btn_do_not_save">取消</string>
+ <string name="btn_delete">删除</string>
+ <string name="btn_no_date">无</string>
<string name="btn_clipboard">剪贴板</string>
<!--menu-->
<string name="menu_help">帮助</string>
@@ -20,11 +51,10 @@
<string name="menu_create_key">创建密钥</string>
<string name="menu_create_key_expert">创建密钥(专家)</string>
<string name="menu_search">搜索</string>
- <string name="menu_share">分享</string>
<string name="menu_copy_to_clipboard">复制到剪贴板</string>
<string name="menu_sign_key">签署密钥</string>
<string name="menu_key_edit_cancel">取消</string>
- <string name="menu_encrypt_to">加密到…</string>
+ <string name="menu_encrypt_to">加密到...</string>
<!--label-->
<string name="label_sign">签署</string>
<string name="label_message">讯息</string>
@@ -64,7 +94,7 @@
<string name="choice_4hours">4小时</string>
<string name="choice_8hours">8小时</string>
<string name="choice_forever">永远</string>
- <string name="filemanager_title_open">打开…</string>
+ <string name="filemanager_title_open">打开...</string>
<string name="warning">警告</string>
<string name="error">错误</string>
<!--sentences-->
@@ -105,14 +135,13 @@
<string name="error_corrupt_data">损坏的数据</string>
<string name="error_wrong_passphrase">错误的密语</string>
<!--progress dialogs, usually ending in '…'-->
- <string name="progress_done">完成。</string>
- <string name="progress_saving">保存…</string>
- <string name="progress_importing">导入中…</string>
- <string name="progress_exporting">导出中…</string>
+ <string name="progress_saving">保存...</string>
+ <string name="progress_importing">导入中...</string>
+ <string name="progress_exporting">导出中...</string>
<string name="progress_building_key">建立密钥</string>
<string name="progress_preparing_master_key">正在准备主密钥</string>
- <string name="progress_verifying_signature">正在验证签名…</string>
- <string name="progress_signing">正在签名…</string>
+ <string name="progress_verifying_signature">正在验证签名...</string>
+ <string name="progress_signing">正在签名...</string>
<string name="progress_reading_data">正在读取数据</string>
<string name="progress_finding_key">正在查找密钥</string>
<string name="progress_querying">正在查询</string>
@@ -157,4 +186,5 @@
<string name="nav_decrypt">解密</string>
<string name="nav_import">导入密钥</string>
<string name="nav_secret_keys">我的密钥</string>
+ <!--hints-->
</resources>
diff --git a/OpenPGP-Keychain/src/main/res/values/arrays.xml b/OpenPGP-Keychain/src/main/res/values/arrays.xml
index 5244de419..c84c2648d 100644
--- a/OpenPGP-Keychain/src/main/res/values/arrays.xml
+++ b/OpenPGP-Keychain/src/main/res/values/arrays.xml
@@ -36,7 +36,7 @@
<item>@string/key_size_4096</item>
</string-array>
<string-array name="import_action_list" translatable="false">
- <item>@string/menu_key_server</item>
+ <item>@string/menu_import_from_key_server</item>
<item>@string/menu_import_from_file</item>
<item>@string/menu_import_from_qr_code</item>
<item>@string/import_from_clipboard</item>
diff --git a/OpenPGP-Keychain/src/main/res/values/attr.xml b/OpenPGP-Keychain/src/main/res/values/attr.xml
new file mode 100644
index 000000000..86622b3e0
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values/attr.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <declare-styleable name="FoldableLinearLayout">
+ <attr name="foldedLabel" format="string" />
+ <attr name="unFoldedLabel" format="string" />
+ <attr name="foldedIcon" format="string" />
+ <attr name="unFoldedIcon" format="string" />
+ </declare-styleable>
+
+</resources> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/values/colors.xml b/OpenPGP-Keychain/src/main/res/values/colors.xml
index 780137181..d1dc6c1f4 100644
--- a/OpenPGP-Keychain/src/main/res/values/colors.xml
+++ b/OpenPGP-Keychain/src/main/res/values/colors.xml
@@ -3,5 +3,5 @@
<color name="emphasis">#31b6e7</color>
<color name="bg_gray">#cecbce</color>
-
+
</resources> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/values/dimens.xml b/OpenPGP-Keychain/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..e1a7749f0
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="drawer_size">240dp</dimen>
+ <dimen name="drawer_content_padding">0dp</dimen>
+</resources> \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml
index f7b0ddc53..2e88062b7 100644
--- a/OpenPGP-Keychain/src/main/res/values/strings.xml
+++ b/OpenPGP-Keychain/src/main/res/values/strings.xml
@@ -17,6 +17,7 @@
<string name="title_change_passphrase">Change Passphrase</string>
<string name="title_set_passphrase">Set Passphrase</string>
<string name="title_send_email">"Send Mail…"</string>
+ <string name="title_send_file">"Send File…"</string>
<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>
@@ -66,6 +67,8 @@
<string name="btn_clipboard">Clipboard</string>
<string name="btn_share">Share with…</string>
<string name="btn_lookup_key">Lookup key</string>
+ <string name="btn_encryption_advanced_settings_show">Show advanced settings</string>
+ <string name="btn_encryption_advanced_settings_hide">Hide advanced settings</string>
<!-- menu -->
<string name="menu_preferences">Settings</string>
@@ -75,15 +78,17 @@
<string name="menu_import">Import</string>
<string name="menu_import_from_nfc">Import from NFC</string>
<string name="menu_export_keys">Export all keys</string>
+ <string name="menu_export_secret_keys">Export all secret keys</string>
<string name="menu_export_key">Export to file</string>
<string name="menu_delete_key">Delete key</string>
<string name="menu_create_key">Create key</string>
<string name="menu_create_key_expert">Create key (expert)</string>
<string name="menu_search">Search</string>
- <string name="menu_key_server">Import from keyserver</string>
+ <string name="menu_import_from_key_server">Keyserver</string>
+ <string name="menu_key_server">Keyserver…</string>
<string name="menu_update_key">Update from keyserver</string>
<string name="menu_export_key_to_server">Upload to key server</string>
- <string name="menu_share">Share</string>
+ <string name="menu_share">Share…</string>
<string name="menu_share_title_fingerprint">Share fingerprint…</string>
<string name="menu_share_title">Share whole key…</string>
<string name="menu_share_default_fingerprint">with…</string>
@@ -110,6 +115,7 @@
<string name="label_select_public_keys">Recipients</string>
<string name="label_delete_after_encryption">Delete After Encryption</string>
<string name="label_delete_after_decryption">Delete After Decryption</string>
+ <string name="label_share_after_encryption">Share After Encryption</string>
<string name="label_encryption_algorithm">Encryption Algorithm</string>
<string name="label_hash_algorithm">Hash Algorithm</string>
<string name="label_asymmetric">Public Key</string>
@@ -128,6 +134,8 @@
<string name="label_name">Name</string>
<string name="label_comment">Comment</string>
<string name="label_email">Email</string>
+ <string name="label_sign_user_id">Sign User Id</string>
+ <string name="label_sign_email">Sign email</string>
<string name="label_send_key">Upload key to selected keyserver after certification</string>
<string name="label_fingerprint">Fingerprint</string>
<string name="select_keys_button_default">Select</string>
@@ -141,11 +149,18 @@
<string name="user_id_no_name">&lt;no name&gt;</string>
<string name="none">&lt;none&gt;</string>
<string name="no_key">&lt;no key&gt;</string>
+ <string name="no_email">&lt;No Email&gt;</string>
<string name="unknown_status"></string>
<string name="can_encrypt">can encrypt</string>
<string name="can_sign">can sign</string>
<string name="expired">expired</string>
<string name="revoked">revoked</string>
+ <string name="user_id">User ID</string>
+
+ <plurals name="n_contacts">
+ <item quantity="one">1 contact</item>
+ <item quantity="other">%d contacts</item>
+ </plurals>
<plurals name="n_key_servers">
<item quantity="one">%d keyserver</item>
@@ -209,6 +224,9 @@
<string name="key_deletion_confirmation_multi">Do you really want to delete all selected keys?\nYou can\'t undo this!</string>
<string name="secret_key_deletion_confirmation">Do you really want to delete the SECRET key \'%s\'?\nYou can\'t undo this!</string>
<string name="ask_save_changed_key">You have made changes to the keyring, would you like to save it?</string>
+ <string name="public_key_deletetion_confirmation">Do you really want to delete the PUBLIC key \'%s\'?\nYou can\'t undo this!</string>
+ <string name="secret_key_delete_text">Delete Secret Keys ?</string>
+ <string name="also_export_secret_keys">Also export secret keys?</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">Successfully added %d key</item>
@@ -232,6 +250,7 @@
<string name="keys_exported">Successfully exported %d keys.</string>
<string name="no_keys_exported">No keys exported.</string>
<string name="key_creation_el_gamal_info">Note: only subkeys support ElGamal, and for ElGamal the nearest keysize of 1536, 2048, 3072, 4096, or 8192 will be used.</string>
+ <string name="key_creation_weak_rsa_info">Note: generating RSA key with length 1024-bit and less is considered unsafe and it\'s disabled for generating new keys.</string>
<string name="key_not_found">Couldn\'t find key %08X.</string>
<plurals name="keys_found">
@@ -270,6 +289,7 @@
<string name="error_master_key_must_not_be_el_gamal">the master key cannot be an ElGamal key</string>
<string name="error_unknown_algorithm_choice">unknown algorithm choice</string>
<string name="error_user_id_needs_a_name">you need to specify a name</string>
+ <string name="error_user_id_no_email">no email found</string>
<string name="error_user_id_needs_an_email_address">you need to specify an email address</string>
<string name="error_key_needs_a_user_id">need at least one user id</string>
<string name="error_main_user_id_must_not_be_empty">main user id must not be empty</string>
@@ -296,18 +316,23 @@
<string name="error_keyserver_insufficient_query">Insufficient server query</string>
<string name="error_keyserver_query">Querying keyserver failed</string>
<string name="error_keyserver_too_many_responses">Too many responses</string>
+ <string name="error_import_file_no_content">File has no content</string>
+ <string name="error_generic_report_bug">A generic error occurred, please create a new bug report for OpenKeychain.</string>
<plurals name="error_can_not_delete_info">
<item quantity="one">Please delete it from the \'My Keys\' screen!</item>
<item quantity="other">Please delete them from the \'My Keys\' screen!</item>
</plurals>
+ <plurals name="error_import_non_pgp_part">
+ <item quantity="one">part of the loaded file is a valid OpenPGP object but not a OpenPGP key</item>
+ <item quantity="other">parts of the loaded file are valid OpenPGP objects but not OpenPGP keys</item>
+ </plurals>
<!-- progress dialogs, usually ending in '…' -->
- <string name="progress_done">done.</string>
- <string name="progress_cancel">cancel</string>
+ <string name="progress_done">Done.</string>
+ <string name="progress_cancel">Cancel</string>
<string name="progress_saving">saving…</string>
<string name="progress_importing">importing…</string>
<string name="progress_exporting">exporting…</string>
- <string name="progress_generating">generating key, this can take up to 3 minutes…</string>
<string name="progress_building_key">building key…</string>
<string name="progress_preparing_master_key">preparing master key…</string>
<string name="progress_certifying_master_key">certifying master key…</string>
@@ -320,6 +345,11 @@
<item quantity="other">exporting keys…</item>
</plurals>
+ <plurals name="progress_generating">
+ <item quantity="one">generating key, this can take up to 3 minutes…</item>
+ <item quantity="other">generating keys, this can take up to 3 minutes…</item>
+ </plurals>
+
<string name="progress_extracting_signature_key">extracting signature key…</string>
<string name="progress_extracting_key">extracting key…</string>
<string name="progress_preparing_streams">preparing streams…</string>
@@ -354,6 +384,7 @@
<!-- Help -->
<string name="help_tab_start">Start</string>
+ <string name="help_tab_faq">FAQ</string>
<string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Changelog</string>
<string name="help_tab_about">About</string>
@@ -386,15 +417,22 @@
<!-- Remote API -->
<string name="api_no_apps">No registered applications!\n\nThird-party applications can request access to OpenKeychain. After granting access, they will be listed here.</string>
+ <string name="api_settings_show_info">Show advanced information</string>
+ <string name="api_settings_hide_info">Hide advanced information</string>
<string name="api_settings_show_advanced">Show advanced settings</string>
<string name="api_settings_hide_advanced">Hide advanced settings</string>
<string name="api_settings_no_key">No key selected</string>
<string name="api_settings_select_key">Select key</string>
+ <string name="api_settings_create_key">Create new key for this account</string>
<string name="api_settings_save">Save</string>
<string name="api_settings_cancel">Cancel</string>
<string name="api_settings_revoke">Revoke access</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_accounts">Accounts</string>
+ <string name="api_settings_accounts_empty">No accounts attached to this application.</string>
+ <string name="api_create_account_text">The application requests the creation of a new account. Please select an existing private key or create a new one.\nApplications are restricted to the usage of keys you select here!</string>
<string name="api_register_text">The displayed application requests access to OpenKeychain.\nAllow access?\n\nWARNING: If you do not know why this screen appeared, disallow access! You can revoke access later using the \'Registered Applications\' screen.</string>
<string name="api_register_allow">Allow access</string>
<string name="api_register_disallow">Disallow access</string>
@@ -424,6 +462,7 @@
<string name="key_list_empty_button_import">importing keys.</string>
<!-- Key view -->
+ <string name="key_view_action_edit">Edit this key</string>
<string name="key_view_action_encrypt">Encrypt to this contact</string>
<string name="key_view_action_certify">Certify this contact\'s key</string>
<string name="key_view_tab_main">Info</string>
@@ -438,5 +477,15 @@
<string name="nav_apps">Registered Apps</string>
<string name="drawer_open">Open navigation drawer</string>
<string name="drawer_close">Close navigation drawer</string>
+ <string name="edit">Edit</string>
+ <string name="my_keys">My Keys</string>
+ <string name="label_secret_key">Secret Key</string>
+ <string name="secret_key_yes">available</string>
+ <string name="secret_key_no">unavailable</string>
+ <string name="section_uids_to_sign">User IDs to sign</string>
+ <string name="progress_re_adding_certs">Reapplying certificates</string>
+
+ <!-- hints -->
+ <string name="encrypt_content_edit_text_hint">Write message here to encrypt…</string>
</resources>