aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-08-01 11:09:25 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-08-01 11:09:25 +0200
commite10cbc54c606563b2d06f083bca17119ca585127 (patch)
tree23c71e67b1c4a381997bdb75de476f05d7dcec5f /OpenKeychain/src
parentbef3e621118d0e4d8fadedf0c9d67b6a9ff41883 (diff)
parentacbf2a18617eea73924dd109e09189420d9876fe (diff)
downloadopen-keychain-e10cbc54c606563b2d06f083bca17119ca585127.tar.gz
open-keychain-e10cbc54c606563b2d06f083bca17119ca585127.tar.bz2
open-keychain-e10cbc54c606563b2d06f083bca17119ca585127.zip
Merge branch 'master' into yubikey
Conflicts: .gitmodules OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
Diffstat (limited to 'OpenKeychain/src')
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml203
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FileImportCache.java97
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java38
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java)24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java)4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java)47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java)18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java)55
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java30
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java187
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java265
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java25
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java76
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java161
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java87
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java81
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java74
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java143
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java59
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java192
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java249
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java214
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java744
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java25
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java30
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java35
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java48
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java102
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java41
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java83
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeActivity.java114
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java155
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java52
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java82
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java45
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java40
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java90
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java46
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java111
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Notify.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java4
-rw-r--r--OpenKeychain/src/main/res/anim/frag_slide_in_from_left.xml8
-rw-r--r--OpenKeychain/src/main/res/anim/frag_slide_in_from_right.xml8
-rw-r--r--OpenKeychain/src/main/res/anim/frag_slide_out_to_left.xml8
-rw-r--r--OpenKeychain/src/main/res/anim/frag_slide_out_to_right.xml8
-rw-r--r--OpenKeychain/src/main/res/anim/qr_code_zoom_enter.xml16
-rw-r--r--OpenKeychain/src/main/res/anim/qr_code_zoom_exit.xml17
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/create_key_robot.pngbin0 -> 2259 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/key_certify_error.pngbin1268 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_depth0.pngbin1252 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_self.pngbin898 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_depth0.pngbin900 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_self.pngbin757 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/key_certify_revoke.pngbin1278 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_lock_closed.pngbin0 -> 675 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_lock_error.pngbin0 -> 748 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_lock_open.pngbin0 -> 675 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired.pngbin0 -> 723 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired_cutout.pngbin0 -> 789 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid.pngbin0 -> 528 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid_cutout.pngbin0 -> 444 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked.pngbin0 -> 714 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked_cutout.pngbin0 -> 861 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown.pngbin0 -> 640 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown_cutout.pngbin0 -> 740 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified.pngbin0 -> 536 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified_cutout.pngbin0 -> 813 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified.pngbin0 -> 541 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified_cutout.pngbin0 -> 695 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-ldpi/key_certify_error.pngbin652 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_depth0.pngbin646 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_self.pngbin507 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-ldpi/key_certify_revoke.pngbin663 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/create_key_robot.pngbin0 -> 1766 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/key_certify_error.pngbin884 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_depth0.pngbin862 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_self.pngbin627 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_depth0.pngbin688 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_self.pngbin555 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/key_certify_revoke.pngbin853 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_lock_closed.pngbin0 -> 528 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_lock_error.pngbin0 -> 622 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_lock_open.pngbin0 -> 522 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired.pngbin0 -> 601 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired_cutout.pngbin0 -> 643 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid.pngbin0 -> 463 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid_cutout.pngbin0 -> 410 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked.pngbin0 -> 613 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked_cutout.pngbin0 -> 685 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown.pngbin0 -> 517 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown_cutout.pngbin0 -> 589 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified.pngbin0 -> 469 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified_cutout.pngbin0 -> 667 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified.pngbin0 -> 476 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified_cutout.pngbin0 -> 557 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/create_key_robot.pngbin0 -> 3176 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/key_certify_error.pngbin1676 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_depth0.pngbin1606 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_self.pngbin1203 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_depth0.pngbin1091 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_self.pngbin940 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/key_certify_revoke.pngbin1646 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_lock_closed.pngbin0 -> 911 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_lock_error.pngbin0 -> 1008 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_lock_open.pngbin0 -> 911 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired.pngbin0 -> 1049 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout.pngbin0 -> 1179 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid.pngbin0 -> 736 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid_cutout.pngbin0 -> 676 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked.pngbin0 -> 1033 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked_cutout.pngbin0 -> 1218 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown.pngbin0 -> 906 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown_cutout.pngbin0 -> 1043 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified.pngbin0 -> 706 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified_cutout.pngbin0 -> 1166 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified.pngbin0 -> 784 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified_cutout.pngbin0 -> 1017 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/create_key_robot.pngbin0 -> 4039 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_error.pngbin2381 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_depth0.pngbin2364 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_self.pngbin2217 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_depth0.pngbin1366 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_self.pngbin1282 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_revoke.pngbin2215 -> 0 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_closed.pngbin0 -> 1160 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_error.pngbin0 -> 1316 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_open.pngbin0 -> 1165 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired.pngbin0 -> 1429 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired_cutout.pngbin0 -> 1590 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid.pngbin0 -> 840 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid_cutout.pngbin0 -> 694 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked.pngbin0 -> 1353 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked_cutout.pngbin0 -> 1660 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown.pngbin0 -> 1231 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown_cutout.pngbin0 -> 1377 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified.pngbin0 -> 946 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified_cutout.pngbin0 -> 1555 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified.pngbin0 -> 1012 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified_cutout.pngbin0 -> 1319 bytes
-rw-r--r--OpenKeychain/src/main/res/layout/api_account_settings_activity.xml30
-rw-r--r--OpenKeychain/src/main/res/layout/api_app_settings_activity.xml50
-rw-r--r--OpenKeychain/src/main/res/layout/certify_key_activity.xml331
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_activity.xml55
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_final_fragment.xml152
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_input_fragment.xml144
-rw-r--r--OpenKeychain/src/main/res/layout/decrypt_result_include.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/edit_key_activity.xml53
-rw-r--r--OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/first_time_activity.xml147
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_activity.xml13
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_fragment.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_header.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_item.xml30
-rw-r--r--OpenKeychain/src/main/res/layout/notify_area.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/qr_code_activity.xml (renamed from OpenKeychain/src/main/res/layout/edit_key_activity_new.xml)11
-rw-r--r--OpenKeychain/src/main/res/layout/share_qr_code_dialog.xml19
-rw-r--r--OpenKeychain/src/main/res/layout/upload_key_activity.xml101
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_activity.xml46
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_main_fragment.xml60
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_share_fragment.xml23
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_user_id_item.xml3
-rw-r--r--OpenKeychain/src/main/res/menu/key_list.xml7
-rw-r--r--OpenKeychain/src/main/res/menu/key_view.xml17
-rw-r--r--OpenKeychain/src/main/res/values-de/strings.xml4
-rw-r--r--OpenKeychain/src/main/res/values-es/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-fr/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-it/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-ja/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-ru/strings.xml8
-rw-r--r--OpenKeychain/src/main/res/values-sl/strings.xml4
-rw-r--r--OpenKeychain/src/main/res/values-uk/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values/colors.xml15
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml81
191 files changed, 3325 insertions, 2525 deletions
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index af09019e8..7af9d895f 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -31,7 +31,7 @@
For OI Filemanager it makes no difference, gpg files can't be associated
-->
- <!-- Specified in buid.gradle -->
+ <!-- Specified in build.gradle -->
<!--<uses-sdk-->
<!--android:minSdkVersion="9"-->
<!--android:targetSdkVersion="19" />-->
@@ -53,10 +53,10 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
- <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
- <uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
- <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
- <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
+ <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
+ <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+ <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
@@ -84,22 +84,23 @@
android:name=".ui.FirstTimeActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/app_name"
- android:windowSoftInputMode="stateHidden" />
+ android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".ui.CreateKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
- android:label="@string/title_create_key"
- android:windowSoftInputMode="stateHidden" />
+ android:label="@string/title_create_key">
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".ui.KeyListActivity" />
+ </activity>
<activity
- android:name=".ui.EditKeyActivityOld"
+ android:name=".ui.EditKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
- android:label="@string/title_edit_key"
- android:windowSoftInputMode="stateHidden" />
+ android:label="@string/title_edit_key" />
<activity
- android:name=".ui.EditKeyActivity"
+ android:name=".ui.QrCodeActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
- android:label="@string/title_edit_key"
- android:windowSoftInputMode="stateHidden" />
+ android:label="@string/share_qr_code_dialog_title" />
<activity
android:name=".ui.ViewKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
@@ -222,7 +223,19 @@
<data android:host="*" />
<data android:scheme="file" />
<data android:scheme="content" />
- <!-- Workaround to match files in pathes with dots in them, like /cdcard/my.folder/test.gpg -->
+
+ <!-- GnuPG ASCII data, mostly keys, but sometimes signatures and encrypted data -->
+ <data android:pathPattern=".*\\.asc" />
+ <data android:pathPattern=".*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <!-- GnuPG binary encrypted/signed data, binary format -->
<data android:pathPattern=".*\\.gpg" />
<data android:pathPattern=".*\\..*\\.gpg" />
<data android:pathPattern=".*\\..*\\..*\\.gpg" />
@@ -233,7 +246,34 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <!-- PGP encrypted data, binary format -->
+ <data android:pathPattern=".*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <!-- on some mail clients, PGP attachments show up as *.bin -->
+ <data android:pathPattern=".*\\.bin" />
+ <data android:pathPattern=".*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
</intent-filter>
+ <!--
+ Some apps will only respect these file associations
+ if the mimeType is not set, and other apps will only respect them if mimeType is set
+ to */*. Therefore we have two whole copies of the same thing, besides setting the mimeType.
+ -->
<intent-filter android:label="@string/intent_decrypt_file">
<action android:name="android.intent.action.VIEW" />
@@ -243,7 +283,10 @@
<data android:host="*" />
<data android:scheme="file" />
<data android:scheme="content" />
+
<data android:mimeType="*/*" />
+
+ <!-- GnuPG ASCII data, mostly keys, but sometimes signatures and encrypted data -->
<data android:pathPattern=".*\\.asc" />
<data android:pathPattern=".*\\..*\\.asc" />
<data android:pathPattern=".*\\..*\\..*\\.asc" />
@@ -254,6 +297,39 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <!-- GnuPG binary encrypted/signed data, binary format -->
+ <data android:pathPattern=".*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <!-- PGP encrypted data, binary format -->
+ <data android:pathPattern=".*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <!-- on some mail clients, PGP attachments show up as *.bin -->
+ <data android:pathPattern=".*\\.bin" />
+ <data android:pathPattern=".*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
</intent-filter>
</activity>
<activity
@@ -323,6 +399,9 @@
<!-- mime type as defined in http://tools.ietf.org/html/rfc3156 -->
<data android:mimeType="application/pgp-keys" />
+ <!-- also link to text/plain, AOSP mail and K-9 mail only give mimeType text/plain
+ when the key file has been manually attached -->
+ <data android:mimeType="text/plain" />
</intent-filter>
<!-- NFC: Handle NFC tags detected from outside our application -->
<intent-filter>
@@ -342,6 +421,19 @@
<data android:host="*" />
<data android:scheme="file" />
<data android:scheme="content" />
+
+ <!-- GnuPG ASCII data, mostly keys, but sometimes signatures and encrypted data -->
+ <data android:pathPattern=".*\\.asc" />
+ <data android:pathPattern=".*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <!-- GnuPG binary encrypted/signed data, binary format -->
<data android:pathPattern=".*\\.gpg" />
<data android:pathPattern=".*\\..*\\.gpg" />
<data android:pathPattern=".*\\..*\\..*\\.gpg" />
@@ -352,8 +444,34 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <!-- PGP encrypted data, binary format -->
+ <data android:pathPattern=".*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <!-- on some mail clients, PGP attachments show up as *.bin -->
+ <data android:pathPattern=".*\\.bin" />
+ <data android:pathPattern=".*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
</intent-filter>
- <!-- VIEW with file endings: *.asc -->
+ <!--
+ Some apps will only respect these file associations
+ if the mimeType is not set, and other apps will only respect them if mimeType is set
+ to */*. Therefore we have two whole copies of the same thing, besides setting the mimeType.
+ -->
<intent-filter android:label="@string/intent_import_key">
<action android:name="android.intent.action.VIEW" />
@@ -363,7 +481,10 @@
<data android:host="*" />
<data android:scheme="file" />
<data android:scheme="content" />
+
<data android:mimeType="*/*" />
+
+ <!-- GnuPG ASCII data, mostly keys, but sometimes signatures and encrypted data -->
<data android:pathPattern=".*\\.asc" />
<data android:pathPattern=".*\\..*\\.asc" />
<data android:pathPattern=".*\\..*\\..*\\.asc" />
@@ -374,7 +495,41 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.asc" />
+ <!-- GnuPG binary encrypted/signed data, binary format -->
+ <data android:pathPattern=".*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpg" />
+ <!-- PGP encrypted data, binary format -->
+ <data android:pathPattern=".*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pgp" />
+ <!-- on some mail clients, PGP attachments show up as *.bin -->
+ <data android:pathPattern=".*\\.bin" />
+ <data android:pathPattern=".*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
+ <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.bin" />
</intent-filter>
+
<!-- Keychain's own Actions -->
<!-- IMPORT_KEY with files TODO: does this work? -->
<intent-filter android:label="@string/intent_import_key">
@@ -469,24 +624,24 @@
<service android:name=".service.DummyAccountService">
<intent-filter>
- <action android:name="android.accounts.AccountAuthenticator"/>
+ <action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
- android:name="android.accounts.AccountAuthenticator"
- android:resource="@xml/account_desc"/>
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/account_desc" />
</service>
<service android:name=".service.ContactSyncAdapterService">
<intent-filter>
- <action android:name="android.content.SyncAdapter"/>
+ <action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
- android:name="android.content.SyncAdapter"
- android:resource="@xml/sync_adapter_desc"/>
+ android:name="android.content.SyncAdapter"
+ android:resource="@xml/sync_adapter_desc" />
<meta-data
- android:name="android.provider.CONTACTS_STRUCTURE"
- android:resource="@xml/custom_pgp_contacts_structure"/>
+ android:name="android.provider.CONTACTS_STRUCTURE"
+ android:resource="@xml/custom_pgp_contacts_structure" />
</service>
</application>
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index 72df3e4b6..a060092a3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -129,7 +129,7 @@ public class Preferences {
editor.commit();
}
- public boolean getFirstTime() {
+ public boolean isFirstTime() {
return mSharedPreferences.getBoolean(Constants.Pref.FIRST_TIME, true);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FileImportCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FileImportCache.java
new file mode 100644
index 000000000..08b8afae7
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FileImportCache.java
@@ -0,0 +1,97 @@
+/*
+ * 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.keyimport;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import org.sufficientlysecure.keychain.KeychainApplication;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * When sending large data (over 1MB) through Androids Binder IPC you get
+ * JavaBinder E !!! FAILED BINDER TRANSACTION !!!
+ * <p/>
+ * To overcome this problem, we cache large Parcelables into a file in our private cache directory
+ * instead of sending them through IPC.
+ */
+public class FileImportCache {
+
+ private Context mContext;
+
+ private static final String FILENAME = "key_import.pcl";
+ private static final String BUNDLE_DATA = "data";
+
+ public FileImportCache(Context context) {
+ this.mContext = context;
+ }
+
+ public void writeCache(ArrayList<ParcelableKeyRing> selectedEntries) throws IOException {
+ Bundle in = new Bundle();
+ in.putParcelableArrayList(BUNDLE_DATA, selectedEntries);
+ File cacheDir = mContext.getCacheDir();
+ if (cacheDir == null) {
+ // https://groups.google.com/forum/#!topic/android-developers/-694j87eXVU
+ throw new IOException("cache dir is null!");
+ }
+ File tempFile = new File(mContext.getCacheDir(), FILENAME);
+
+ FileOutputStream fos = new FileOutputStream(tempFile);
+ Parcel p = Parcel.obtain(); // creating empty parcel object
+ in.writeToParcel(p, 0); // saving bundle as parcel
+ fos.write(p.marshall()); // writing parcel to file
+ fos.flush();
+ fos.close();
+ }
+
+ public List<ParcelableKeyRing> readCache() throws IOException {
+ Parcel parcel = Parcel.obtain(); // creating empty parcel object
+ Bundle out;
+ File cacheDir = mContext.getCacheDir();
+ if (cacheDir == null) {
+ // https://groups.google.com/forum/#!topic/android-developers/-694j87eXVU
+ throw new IOException("cache dir is null!");
+ }
+
+ File tempFile = new File(cacheDir, FILENAME);
+ try {
+ FileInputStream fis = new FileInputStream(tempFile);
+ byte[] array = new byte[(int) fis.getChannel().size()];
+ fis.read(array, 0, array.length);
+ fis.close();
+
+ parcel.unmarshall(array, 0, array.length);
+ parcel.setDataPosition(0);
+ out = parcel.readBundle(KeychainApplication.class.getClassLoader());
+ out.putAll(out);
+
+ return out.getParcelableArrayList(BUNDLE_DATA);
+ } finally {
+ parcel.recycle();
+ // delete temp file
+ tempFile.delete();
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
index 44679ba18..41f1e6997 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
@@ -22,6 +22,7 @@ import de.measite.minidns.Client;
import de.measite.minidns.Question;
import de.measite.minidns.Record;
import de.measite.minidns.record.SRV;
+
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.helper.TlsHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
@@ -102,8 +103,9 @@ public class HkpKeyserver extends Keyserver {
*/
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]*)[ \n\r]*)+)", // one or more uid lines
- Pattern.CASE_INSENSITIVE);
+ + "((uid:([^:]*):([0-9]+):([0-9]*):([rde]*)[ \n\r]*)+)", // one or more uid lines
+ Pattern.CASE_INSENSITIVE
+ );
/**
* uid:%escaped uid string%:%creationdate%:%expirationdate%:%flags%
@@ -215,10 +217,18 @@ public class HkpKeyserver extends Keyserver {
throw new HttpError(response, data);
}
} catch (IOException e) {
- throw new QueryFailedException("querying server(s) for '" + mHost + "' failed");
+ throw new QueryFailedException("Keyserver '" + mHost + "' is unavailable. Check your Internet connection!");
}
}
+ /**
+ * Results are sorted by creation date of key!
+ *
+ * @param query
+ * @return
+ * @throws QueryFailedException
+ * @throws QueryNeedsRepairException
+ */
@Override
public ArrayList<ImportKeysListEntry> search(String query) throws QueryFailedException,
QueryNeedsRepairException {
@@ -240,18 +250,26 @@ public class HkpKeyserver extends Keyserver {
try {
data = query(request);
} catch (HttpError e) {
- if (e.getCode() == 404) {
- return results;
- } else {
+ if (e.getData() != null) {
+ Log.d(Constants.TAG, "returned error data: " + e.getData().toLowerCase(Locale.US));
+
if (e.getData().toLowerCase(Locale.US).contains("no keys found")) {
+ // NOTE: This is also a 404 error for some keyservers!
return results;
} else if (e.getData().toLowerCase(Locale.US).contains("too many")) {
throw new TooManyResponsesException();
} else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) {
throw new QueryTooShortException();
+ } else if (e.getCode() == 404) {
+ // NOTE: handle this 404 at last, maybe it was a "no keys found" error
+ throw new QueryFailedException("Keyserver '" + mHost + "' not found. Error 404");
+ } else {
+ // NOTE: some keyserver do not provide a more detailed error response
+ throw new QueryTooShortOrTooManyResponsesException();
}
}
- throw new QueryFailedException("querying server(s) for '" + mHost + "' failed");
+
+ throw new QueryFailedException("Querying server(s) for '" + mHost + "' failed.");
}
final Matcher matcher = PUB_KEY_LINE.matcher(data);
@@ -267,9 +285,9 @@ public class HkpKeyserver extends Keyserver {
// group 1 contains the full fingerprint (v4) or the long key id if available
// see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
- String fingerprintOrKeyId = matcher.group(1);
+ String fingerprintOrKeyId = matcher.group(1).toLowerCase(Locale.US);
if (fingerprintOrKeyId.length() > 16) {
- entry.setFingerprintHex(fingerprintOrKeyId.toLowerCase(Locale.US));
+ entry.setFingerprintHex(fingerprintOrKeyId);
entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length()
- 16, fingerprintOrKeyId.length()));
} else {
@@ -291,7 +309,7 @@ public class HkpKeyserver extends Keyserver {
while (uidMatcher.find()) {
String tmp = uidMatcher.group(1).trim();
if (tmp.contains("%")) {
- if(tmp.contains("%%")) {
+ if (tmp.contains("%%")) {
// This is a fix for issue #683
// The server encodes a percent sign as %%, so it is swapped out with its
// urlencoded counterpart to prevent errors
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
index 842e7d922..b726529f8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
@@ -44,6 +44,13 @@ public abstract class Keyserver {
private static final long serialVersionUID = 2703768928624654514L;
}
+ /**
+ * query too short _or_ too many responses
+ */
+ public static class QueryTooShortOrTooManyResponsesException extends QueryNeedsRepairException {
+ private static final long serialVersionUID = 2703768928624654514L;
+ }
+
public static class AddKeyException extends Exception {
private static final long serialVersionUID = -507574859137295530L;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
index a054255dc..ee0dfefa4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
@@ -16,13 +16,11 @@ import java.io.OutputStream;
* getter method.
*
*/
-public abstract class WrappedKeyRing extends KeyRing {
+public abstract class CanonicalizedKeyRing extends KeyRing {
- private final boolean mHasAnySecret;
private final int mVerified;
- WrappedKeyRing(boolean hasAnySecret, int verified) {
- mHasAnySecret = hasAnySecret;
+ CanonicalizedKeyRing(int verified) {
mVerified = verified;
}
@@ -30,10 +28,6 @@ public abstract class WrappedKeyRing extends KeyRing {
return getRing().getPublicKey().getKeyID();
}
- public boolean hasAnySecret() {
- return mHasAnySecret;
- }
-
public int getVerified() {
return mVerified;
}
@@ -56,7 +50,7 @@ public abstract class WrappedKeyRing extends KeyRing {
}
public long getEncryptId() throws PgpGeneralException {
- for(WrappedPublicKey key : publicKeyIterator()) {
+ for(CanonicalizedPublicKey key : publicKeyIterator()) {
if(key.canEncrypt()) {
return key.getKeyId();
}
@@ -74,7 +68,7 @@ public abstract class WrappedKeyRing extends KeyRing {
}
public long getSignId() throws PgpGeneralException {
- for(WrappedPublicKey key : publicKeyIterator()) {
+ for(CanonicalizedPublicKey key : publicKeyIterator()) {
if(key.canSign()) {
return key.getKeyId();
}
@@ -103,14 +97,14 @@ public abstract class WrappedKeyRing extends KeyRing {
abstract PGPKeyRing getRing();
- abstract public IterableIterator<WrappedPublicKey> publicKeyIterator();
+ abstract public IterableIterator<CanonicalizedPublicKey> publicKeyIterator();
- public WrappedPublicKey getPublicKey() {
- return new WrappedPublicKey(this, getRing().getPublicKey());
+ public CanonicalizedPublicKey getPublicKey() {
+ return new CanonicalizedPublicKey(this, getRing().getPublicKey());
}
- public WrappedPublicKey getPublicKey(long id) {
- return new WrappedPublicKey(this, getRing().getPublicKey(id));
+ public CanonicalizedPublicKey getPublicKey(long id) {
+ return new CanonicalizedPublicKey(this, getRing().getPublicKey(id));
}
public byte[] getEncoded() throws IOException {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
index 69a4fbdee..981caad49 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
@@ -14,12 +14,12 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
* stored in the database.
*
*/
-public class WrappedPublicKey extends UncachedPublicKey {
+public class CanonicalizedPublicKey extends UncachedPublicKey {
// this is the parent key ring
final KeyRing mRing;
- WrappedPublicKey(KeyRing ring, PGPPublicKey key) {
+ CanonicalizedPublicKey(KeyRing ring, PGPPublicKey key) {
super(key);
mRing = ring;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
index 57d84072a..70288dceb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
@@ -1,42 +1,45 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.util.IterableIterator;
-import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
import java.util.Iterator;
-public class WrappedPublicKeyRing extends WrappedKeyRing {
+public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {
private PGPPublicKeyRing mRing;
- private final byte[] mPubKey;
- public WrappedPublicKeyRing(byte[] blob, boolean hasAnySecret, int verified) {
- super(hasAnySecret, verified);
- mPubKey = blob;
+ CanonicalizedPublicKeyRing(PGPPublicKeyRing ring, int verified) {
+ super(verified);
+ mRing = ring;
}
- PGPPublicKeyRing getRing() {
+ public CanonicalizedPublicKeyRing(byte[] blob, int verified) {
+ super(verified);
if(mRing == null) {
- PGPObjectFactory factory = new PGPObjectFactory(mPubKey);
- PGPKeyRing keyRing = null;
+ // get first object in block
+ PGPObjectFactory factory = new PGPObjectFactory(blob);
try {
- if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) {
- Log.e(Constants.TAG, "No keys given!");
+ Object obj = factory.nextObject();
+ if (! (obj instanceof PGPPublicKeyRing)) {
+ throw new RuntimeException("Error constructing CanonicalizedPublicKeyRing, should never happen!");
+ }
+ mRing = (PGPPublicKeyRing) obj;
+ if (factory.nextObject() != null) {
+ throw new RuntimeException("Encountered trailing data after keyring, should never happen!");
}
} catch (IOException e) {
- Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e);
+ throw new RuntimeException("IO Error constructing CanonicalizedPublicKeyRing, should never happen!");
}
-
- mRing = (PGPPublicKeyRing) keyRing;
}
+ }
+
+ PGPPublicKeyRing getRing() {
return mRing;
}
@@ -45,10 +48,10 @@ public class WrappedPublicKeyRing extends WrappedKeyRing {
}
/** Getter that returns the subkey that should be used for signing. */
- WrappedPublicKey getEncryptionSubKey() throws PgpGeneralException {
+ CanonicalizedPublicKey getEncryptionSubKey() throws PgpGeneralException {
PGPPublicKey key = getRing().getPublicKey(getEncryptId());
if(key != null) {
- WrappedPublicKey cKey = new WrappedPublicKey(this, key);
+ CanonicalizedPublicKey cKey = new CanonicalizedPublicKey(this, key);
if(!cKey.canEncrypt()) {
throw new PgpGeneralException("key error");
}
@@ -57,18 +60,18 @@ public class WrappedPublicKeyRing extends WrappedKeyRing {
throw new PgpGeneralException("no encryption key available");
}
- public IterableIterator<WrappedPublicKey> publicKeyIterator() {
+ public IterableIterator<CanonicalizedPublicKey> publicKeyIterator() {
@SuppressWarnings("unchecked")
final Iterator<PGPPublicKey> it = getRing().getPublicKeys();
- return new IterableIterator<WrappedPublicKey>(new Iterator<WrappedPublicKey>() {
+ return new IterableIterator<CanonicalizedPublicKey>(new Iterator<CanonicalizedPublicKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
- public WrappedPublicKey next() {
- return new WrappedPublicKey(WrappedPublicKeyRing.this, it.next());
+ public CanonicalizedPublicKey next() {
+ return new CanonicalizedPublicKey(CanonicalizedPublicKeyRing.this, it.next());
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index cc6313b32..ff82da07a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -43,7 +43,7 @@ import java.util.List;
* properly imported secret keys only.
*
*/
-public class WrappedSecretKey extends WrappedPublicKey {
+public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
private final PGPSecretKey mSecretKey;
private PGPPrivateKey mPrivateKey = null;
@@ -53,21 +53,13 @@ public class WrappedSecretKey extends WrappedPublicKey {
private static int PRIVATE_KEY_STATE_UNLOCKED = 1;
private static int PRIVATE_KEY_STATE_DIVERT_TO_CARD = 2;
- WrappedSecretKey(WrappedSecretKeyRing ring, PGPSecretKey key) {
+ CanonicalizedSecretKey(CanonicalizedSecretKeyRing ring, PGPSecretKey key) {
super(ring, key.getPublicKey());
mSecretKey = key;
}
- public WrappedSecretKeyRing getRing() {
- return (WrappedSecretKeyRing) mRing;
- }
-
- /** Returns the wrapped PGPSecretKeyRing.
- * This function is for compatibility only, should not be used anymore and will be removed
- */
- @Deprecated
- public PGPSecretKey getKeyExternal() {
- return mSecretKey;
+ public CanonicalizedSecretKeyRing getRing() {
+ return (CanonicalizedSecretKeyRing) mRing;
}
/**
@@ -189,7 +181,7 @@ public class WrappedSecretKey extends WrappedPublicKey {
* @param userIds User IDs to certify, must not be null or empty
* @return A keyring with added certifications
*/
- public UncachedKeyRing certifyUserIds(WrappedPublicKeyRing publicKeyRing, List<String> userIds)
+ public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds)
throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException,
PGPException, SignatureException {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
index 5cb24cf88..7d3e26000 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
@@ -1,10 +1,12 @@
package org.sufficientlysecure.keychain.pgp;
+import org.spongycastle.bcpg.S2K;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
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.operator.PBESecretKeyDecryptor;
@@ -15,15 +17,21 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
+import java.util.HashSet;
import java.util.Iterator;
-public class WrappedSecretKeyRing extends WrappedKeyRing {
+public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing {
private PGPSecretKeyRing mRing;
- public WrappedSecretKeyRing(byte[] blob, boolean isRevoked, int verified)
+ CanonicalizedSecretKeyRing(PGPSecretKeyRing ring, int verified) {
+ super(verified);
+ mRing = ring;
+ }
+
+ public CanonicalizedSecretKeyRing(byte[] blob, boolean isRevoked, int verified)
{
- super(isRevoked, verified);
+ super(verified);
PGPObjectFactory factory = new PGPObjectFactory(blob);
PGPKeyRing keyRing = null;
try {
@@ -41,19 +49,32 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
return mRing;
}
- public WrappedSecretKey getSecretKey() {
- return new WrappedSecretKey(this, mRing.getSecretKey());
+ public CanonicalizedSecretKey getSecretKey() {
+ return new CanonicalizedSecretKey(this, mRing.getSecretKey());
+ }
+
+ public CanonicalizedSecretKey getSecretKey(long id) {
+ return new CanonicalizedSecretKey(this, mRing.getSecretKey(id));
}
- public WrappedSecretKey getSecretKey(long id) {
- return new WrappedSecretKey(this, mRing.getSecretKey(id));
+ public HashSet<Long> getAvailableSubkeys() {
+ HashSet<Long> result = new HashSet<Long>();
+ // then, mark exactly the keys we have available
+ for (PGPSecretKey sub : new IterableIterator<PGPSecretKey>(getRing().getSecretKeys())) {
+ S2K s2k = sub.getS2K();
+ // add key, except if the private key has been stripped (GNU extension)
+ if(s2k == null || (s2k.getProtectionMode() != S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY)) {
+ result.add(sub.getKeyID());
+ }
+ }
+ return result;
}
/** Getter that returns the subkey that should be used for signing. */
- WrappedSecretKey getSigningSubKey() throws PgpGeneralException {
+ CanonicalizedSecretKey getSigningSubKey() throws PgpGeneralException {
PGPSecretKey key = mRing.getSecretKey(getSignId());
if(key != null) {
- WrappedSecretKey cKey = new WrappedSecretKey(this, key);
+ CanonicalizedSecretKey cKey = new CanonicalizedSecretKey(this, key);
if(!cKey.canSign()) {
throw new PgpGeneralException("key error");
}
@@ -88,17 +109,17 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
}
}
- public IterableIterator<WrappedSecretKey> secretKeyIterator() {
+ public IterableIterator<CanonicalizedSecretKey> secretKeyIterator() {
final Iterator<PGPSecretKey> it = mRing.getSecretKeys();
- return new IterableIterator<WrappedSecretKey>(new Iterator<WrappedSecretKey>() {
+ return new IterableIterator<CanonicalizedSecretKey>(new Iterator<CanonicalizedSecretKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
- public WrappedSecretKey next() {
- return new WrappedSecretKey(WrappedSecretKeyRing.this, it.next());
+ public CanonicalizedSecretKey next() {
+ return new CanonicalizedSecretKey(CanonicalizedSecretKeyRing.this, it.next());
}
@Override
@@ -108,17 +129,17 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
});
}
- public IterableIterator<WrappedPublicKey> publicKeyIterator() {
+ public IterableIterator<CanonicalizedPublicKey> publicKeyIterator() {
final Iterator<PGPPublicKey> it = getRing().getPublicKeys();
- return new IterableIterator<WrappedPublicKey>(new Iterator<WrappedPublicKey>() {
+ return new IterableIterator<CanonicalizedPublicKey>(new Iterator<CanonicalizedPublicKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
- public WrappedPublicKey next() {
- return new WrappedPublicKey(WrappedSecretKeyRing.this, it.next());
+ public CanonicalizedPublicKey next() {
+ return new CanonicalizedPublicKey(CanonicalizedSecretKeyRing.this, it.next());
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
index 129ffba3e..ebc49ab05 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
@@ -12,7 +12,7 @@ import java.util.regex.Pattern;
* keyring should in all cases agree on the output of all methods described
* here.
*
- * @see org.sufficientlysecure.keychain.pgp.WrappedKeyRing
+ * @see CanonicalizedKeyRing
* @see org.sufficientlysecure.keychain.provider.CachedPublicKeyRing
*
*/
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index db9e2c6c6..7f2d971ed 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -231,7 +231,7 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
PGPPBEEncryptedData encryptedDataSymmetric = null;
- WrappedSecretKey secretEncryptionKey = null;
+ CanonicalizedSecretKey secretEncryptionKey = null;
Iterator<?> it = enc.getEncryptedDataObjects();
boolean asymmetricPacketFound = false;
boolean symmetricPacketFound = false;
@@ -243,10 +243,10 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
- WrappedSecretKeyRing secretKeyRing;
+ CanonicalizedSecretKeyRing secretKeyRing;
try {
// get actual keyring object based on master key id
- secretKeyRing = mProviderHelper.getWrappedSecretKeyRing(
+ secretKeyRing = mProviderHelper.getCanonicalizedSecretKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(encData.getKeyID())
);
} catch (ProviderHelper.NotFoundException e) {
@@ -365,8 +365,8 @@ public class PgpDecryptVerify {
Object dataChunk = plainFact.nextObject();
OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
int signatureIndex = -1;
- WrappedPublicKeyRing signingRing = null;
- WrappedPublicKey signingKey = null;
+ CanonicalizedPublicKeyRing signingRing = null;
+ CanonicalizedPublicKey signingKey = null;
if (dataChunk instanceof PGPCompressedData) {
updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
@@ -390,7 +390,7 @@ public class PgpDecryptVerify {
for (int i = 0; i < sigList.size(); ++i) {
try {
long sigKeyId = sigList.get(i).getKeyID();
- signingRing = mProviderHelper.getWrappedPublicKeyRing(
+ signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
signingKey = signingRing.getPublicKey(sigKeyId);
@@ -566,8 +566,8 @@ public class PgpDecryptVerify {
throw new InvalidDataException();
}
- WrappedPublicKeyRing signingRing = null;
- WrappedPublicKey signingKey = null;
+ CanonicalizedPublicKeyRing signingRing = null;
+ CanonicalizedPublicKey signingKey = null;
int signatureIndex = -1;
// go through all signatures
@@ -575,7 +575,7 @@ public class PgpDecryptVerify {
for (int i = 0; i < sigList.size(); ++i) {
try {
long sigKeyId = sigList.get(i).getKeyID();
- signingRing = mProviderHelper.getWrappedPublicKeyRing(
+ signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
signingKey = signingRing.getPublicKey(sigKeyId);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index 6fc55cfb8..846b00ef2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -34,7 +34,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
-import org.sufficientlysecure.keychain.service.OperationResults.ImportResult;
+import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -93,7 +93,7 @@ public class PgpImportExport {
}
}
- public boolean uploadKeyRingToServer(HkpKeyserver server, WrappedPublicKeyRing keyring) {
+ public boolean uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
try {
@@ -123,14 +123,14 @@ public class PgpImportExport {
}
/** Imports keys from given data. If keyIds is given only those are imported */
- public ImportResult importKeyRings(List<ParcelableKeyRing> entries) {
+ public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries) {
updateProgress(R.string.progress_importing, 0, 100);
// If there aren't even any keys, do nothing here.
if (entries == null || entries.size() == 0) {
- return new ImportResult(
- ImportResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
+ return new ImportKeyResult(
+ ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
}
int newKeys = 0, oldKeys = 0, badKeys = 0;
@@ -185,26 +185,26 @@ public class PgpImportExport {
int resultType = 0;
// special return case: no new keys at all
if (badKeys == 0 && newKeys == 0 && oldKeys == 0) {
- resultType = ImportResult.RESULT_FAIL_NOTHING;
+ resultType = ImportKeyResult.RESULT_FAIL_NOTHING;
} else {
if (newKeys > 0) {
- resultType |= ImportResult.RESULT_OK_NEWKEYS;
+ resultType |= ImportKeyResult.RESULT_OK_NEWKEYS;
}
if (oldKeys > 0) {
- resultType |= ImportResult.RESULT_OK_UPDATED;
+ resultType |= ImportKeyResult.RESULT_OK_UPDATED;
}
if (badKeys > 0) {
- resultType |= ImportResult.RESULT_WITH_ERRORS;
+ resultType |= ImportKeyResult.RESULT_WITH_ERRORS;
if (newKeys == 0 && oldKeys == 0) {
- resultType |= ImportResult.RESULT_ERROR;
+ resultType |= ImportKeyResult.RESULT_ERROR;
}
}
if (log.containsWarnings()) {
- resultType |= ImportResult.RESULT_WITH_WARNINGS;
+ resultType |= ImportKeyResult.RESULT_WITH_WARNINGS;
}
}
- return new ImportResult(resultType, log, newKeys, oldKeys, badKeys);
+ return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys);
}
@@ -235,7 +235,7 @@ public class PgpImportExport {
updateProgress(progress * 100 / masterKeyIdsSize, 100);
try {
- WrappedPublicKeyRing ring = mProviderHelper.getWrappedPublicKeyRing(
+ CanonicalizedPublicKeyRing ring = mProviderHelper.getCanonicalizedPublicKeyRing(
KeychainContract.KeyRings.buildUnifiedKeyRingUri(pubKeyMasterId)
);
@@ -263,8 +263,8 @@ public class PgpImportExport {
updateProgress(progress * 100 / masterKeyIdsSize, 100);
try {
- WrappedSecretKeyRing secretKeyRing =
- mProviderHelper.getWrappedSecretKeyRing(secretKeyMasterId);
+ CanonicalizedSecretKeyRing secretKeyRing =
+ mProviderHelper.getCanonicalizedSecretKeyRing(secretKeyMasterId);
secretKeyRing.encode(arOutStream);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index 00f73a5b0..861f93446 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -46,15 +46,17 @@ import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Primes;
+import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.IOException;
import java.math.BigInteger;
@@ -67,6 +69,7 @@ import java.security.SignatureException;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
+import java.util.Stack;
/**
* This class is the single place where ALL operations that actually modify a PGP public or secret
@@ -78,7 +81,7 @@ import java.util.Iterator;
* This indicator may be null.
*/
public class PgpKeyOperation {
- private Progressable mProgress;
+ private Stack<Progressable> mProgress;
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
@@ -92,13 +95,34 @@ public class PgpKeyOperation {
public PgpKeyOperation(Progressable progress) {
super();
- this.mProgress = progress;
+ if (progress != null) {
+ mProgress = new Stack<Progressable>();
+ mProgress.push(progress);
+ }
}
- void updateProgress(int message, int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(message, current, total);
+ private void subProgressPush(int from, int to) {
+ if (mProgress == null) {
+ return;
+ }
+ mProgress.push(new ProgressScaler(mProgress.peek(), from, to, 100));
+ }
+ private void subProgressPop() {
+ if (mProgress == null) {
+ return;
}
+ if (mProgress.size() == 1) {
+ throw new RuntimeException("Tried to pop progressable without prior push! "
+ + "This is a programming error, please file a bug report.");
+ }
+ mProgress.pop();
+ }
+
+ private void progress(int message, int current) {
+ if (mProgress == null) {
+ return;
+ }
+ mProgress.peek().setProgress(message, current, 100);
}
/** Creates new secret key. */
@@ -115,6 +139,7 @@ public class PgpKeyOperation {
switch (algorithmChoice) {
case Constants.choice.algorithm.dsa: {
+ progress(R.string.progress_generating_dsa, 30);
keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
keyGen.initialize(keySize, new SecureRandom());
algorithm = PGPPublicKey.DSA;
@@ -122,6 +147,7 @@ public class PgpKeyOperation {
}
case Constants.choice.algorithm.elgamal: {
+ progress(R.string.progress_generating_elgamal, 30);
keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
BigInteger p = Primes.getBestPrime(keySize);
BigInteger g = new BigInteger("2");
@@ -134,6 +160,7 @@ public class PgpKeyOperation {
}
case Constants.choice.algorithm.rsa: {
+ progress(R.string.progress_generating_rsa, 30);
keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
keyGen.initialize(keySize, new SecureRandom());
@@ -163,43 +190,49 @@ public class PgpKeyOperation {
}
}
- public UncachedKeyRing createSecretKeyRing(SaveKeyringParcel saveParcel, OperationLog log,
- int indent) {
+ public EditKeyResult createSecretKeyRing(SaveKeyringParcel saveParcel) {
+
+ OperationLog log = new OperationLog();
+ int indent = 0;
try {
log.add(LogLevel.START, LogType.MSG_CR, indent);
+ progress(R.string.progress_building_key, 0);
indent += 1;
- updateProgress(R.string.progress_building_key, 0, 100);
if (saveParcel.mAddSubKeys.isEmpty()) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_MASTER, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
if (saveParcel.mAddUserIds.isEmpty()) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_USER_ID, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
SubkeyAdd add = saveParcel.mAddSubKeys.remove(0);
if ((add.mFlags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_CERTIFY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
if (add.mAlgorithm == Constants.choice.algorithm.elgamal) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_MASTER_ELGAMAL, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ subProgressPush(10, 30);
PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ subProgressPop();
// return null if this failed (an error will already have been logged by createKey)
if (keyPair == null) {
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ progress(R.string.progress_building_master_key, 40);
+
// define hashing and signing algos
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
.build().get(HashAlgorithmTags.SHA1);
@@ -213,15 +246,16 @@ public class PgpKeyOperation {
PGPSecretKeyRing sKR = new PGPSecretKeyRing(
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
- return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log, indent);
+ subProgressPush(50, 100);
+ return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log);
} catch (PGPException e) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
Log.e(Constants.TAG, "pgp error encoding key", e);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (IOException e) {
Log.e(Constants.TAG, "io error encoding key", e);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
}
@@ -237,8 +271,11 @@ public class PgpKeyOperation {
* are changed by adding new certificates, which implicitly override older certificates.
*
*/
- public UncachedKeyRing modifySecretKeyRing(WrappedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
- String passphrase, OperationLog log, int indent) {
+ public EditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
+ String passphrase) {
+
+ OperationLog log = new OperationLog();
+ int indent = 0;
/*
* 1. Unlock private key
@@ -251,14 +288,15 @@ public class PgpKeyOperation {
* 6. If requested, change passphrase
*/
- log.add(LogLevel.START, LogType.MSG_MF, indent);
+ log.add(LogLevel.START, LogType.MSG_MF, indent,
+ PgpKeyHelper.convertKeyIdToHex(wsKR.getMasterKeyId()));
indent += 1;
- updateProgress(R.string.progress_building_key, 0, 100);
+ progress(R.string.progress_building_key, 0);
// Make sure this is called with a proper SaveKeyringParcel
if (saveParcel.mMasterKeyId == null || saveParcel.mMasterKeyId != wsKR.getMasterKeyId()) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_KEYID, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// We work on bouncycastle object level here
@@ -270,27 +308,30 @@ public class PgpKeyOperation {
|| !Arrays.equals(saveParcel.mFingerprint,
masterSecretKey.getPublicKey().getFingerprint())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_FINGERPRINT, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// read masterKeyFlags, and use the same as before.
// since this is the master key, this contains at least CERTIFY_OTHER
int masterKeyFlags = readKeyFlags(masterSecretKey.getPublicKey()) | KeyFlags.CERTIFY_OTHER;
- return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log, indent);
+ return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log);
}
- private UncachedKeyRing internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
+ private EditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
int masterKeyFlags,
SaveKeyringParcel saveParcel, String passphrase,
- OperationLog log, int indent) {
+ OperationLog log) {
+
+ int indent = 1;
- updateProgress(R.string.progress_certifying_master_key, 20, 100);
+ progress(R.string.progress_modify, 0);
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
// 1. Unlock private key
+ progress(R.string.progress_modify_unlock, 10);
log.add(LogLevel.DEBUG, LogType.MSG_MF_UNLOCK, indent);
PGPPrivateKey masterPrivateKey;
{
@@ -300,7 +341,7 @@ public class PgpKeyOperation {
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) {
log.add(LogLevel.ERROR, LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
}
@@ -310,9 +351,18 @@ public class PgpKeyOperation {
PGPPublicKey modifiedPublicKey = masterPublicKey;
// 2a. Add certificates for new user ids
- for (String userId : saveParcel.mAddUserIds) {
+ subProgressPush(15, 25);
+ for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
+
+ progress(R.string.progress_modify_adduid, (i-1) * (100 / saveParcel.mAddUserIds.size()));
+ String userId = saveParcel.mAddUserIds.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent);
+ if (userId.equals("")) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent+1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
// this operation supersedes all previous binding and revocation certificates,
// so remove those to retain assertions from canonicalization for later operations
@SuppressWarnings("unchecked")
@@ -322,7 +372,7 @@ public class PgpKeyOperation {
if (cert.getKeyID() != masterPublicKey.getKeyID()) {
// foreign certificate?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
|| cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
@@ -343,19 +393,27 @@ public class PgpKeyOperation {
masterPublicKey, userId, isPrimary, masterKeyFlags);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
}
+ subProgressPop();
// 2b. Add revocations for revoked user ids
- for (String userId : saveParcel.mRevokeUserIds) {
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent);
+ subProgressPush(25, 40);
+ for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
+
+ progress(R.string.progress_modify_revokeuid, (i-1) * (100 / saveParcel.mRevokeUserIds.size()));
+ String userId = saveParcel.mRevokeUserIds.get(i);
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
+
// a duplicate revocation will be removed during canonicalization, so no need to
// take care of that here.
PGPSignature cert = generateRevocationSignature(masterPrivateKey,
masterPublicKey, userId);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
}
+ subProgressPop();
// 3. If primary user id changed, generate new certificates for both old and new
if (saveParcel.mChangePrimaryUserId != null) {
+ progress(R.string.progress_modify_primaryuid, 40);
// keep track if we actually changed one
boolean ok = false;
@@ -373,7 +431,7 @@ public class PgpKeyOperation {
if (cert.getKeyID() != masterPublicKey.getKeyID()) {
// foreign certificate?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// we know from canonicalization that if there is any revocation here, it
// is valid and not superseded by a newer certification.
@@ -394,7 +452,7 @@ public class PgpKeyOperation {
if (currentCert == null) {
// no certificate found?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// we definitely should not update certifications of revoked keys, so just leave it.
@@ -402,13 +460,14 @@ public class PgpKeyOperation {
// revoked user ids cannot be primary!
if (userId.equals(saveParcel.mChangePrimaryUserId)) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
continue;
}
// if this is~ the/a primary user id
- if (currentCert.hasSubpackets() && currentCert.getHashedSubPackets().isPrimaryUserID()) {
+ if (currentCert.getHashedSubPackets() != null
+ && currentCert.getHashedSubPackets().isPrimaryUserID()) {
// if it's the one we want, just leave it as is
if (userId.equals(saveParcel.mChangePrimaryUserId)) {
ok = true;
@@ -448,7 +507,7 @@ public class PgpKeyOperation {
if (!ok) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
}
@@ -460,21 +519,25 @@ public class PgpKeyOperation {
}
// 4a. For each subkey change, generate new subkey binding certificate
- for (SaveKeyringParcel.SubkeyChange change : saveParcel.mChangeSubKeys) {
+ subProgressPush(50, 60);
+ for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) {
+
+ progress(R.string.progress_modify_subkeychange, (i-1) * (100 / saveParcel.mChangeSubKeys.size()));
+ SaveKeyringParcel.SubkeyChange change = saveParcel.mChangeSubKeys.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE,
indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
// TODO allow changes in master key? this implies generating new user id certs...
if (change.mKeyId == masterPublicKey.getKeyID()) {
Log.e(Constants.TAG, "changing the master key not supported");
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
if (sKey == null) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
PGPPublicKey pKey = sKey.getPublicKey();
@@ -482,7 +545,7 @@ public class PgpKeyOperation {
if (change.mExpiry != null && new Date(change.mExpiry*1000).before(new Date())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// keep old flags, or replace with new ones
@@ -514,16 +577,22 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
+ subProgressPop();
// 4b. For each subkey revocation, generate new subkey revocation certificate
- for (long revocation : saveParcel.mRevokeSubKeys) {
+ subProgressPush(60, 70);
+ for (int i = 0; i < saveParcel.mRevokeSubKeys.size(); i++) {
+
+ progress(R.string.progress_modify_subkeyrevoke, (i-1) * (100 / saveParcel.mRevokeSubKeys.size()));
+ long revocation = saveParcel.mRevokeSubKeys.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_REVOKE,
indent, PgpKeyHelper.convertKeyIdToHex(revocation));
+
PGPSecretKey sKey = sKR.getSecretKey(revocation);
if (sKey == null) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
indent+1, PgpKeyHelper.convertKeyIdToHex(revocation));
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
PGPPublicKey pKey = sKey.getPublicKey();
@@ -533,21 +602,30 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
+ subProgressPop();
// 5. Generate and add new subkeys
- for (SaveKeyringParcel.SubkeyAdd add : saveParcel.mAddSubKeys) {
+ subProgressPush(70, 90);
+ for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) {
+
+ progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
+ SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(0);
+ log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
if (add.mExpiry != null && new Date(add.mExpiry*1000).before(new Date())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, indent +1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
-
// generate a new secret key (privkey only for now)
+ subProgressPush(
+ (i-1) * (100 / saveParcel.mAddSubKeys.size()),
+ i * (100 / saveParcel.mAddSubKeys.size())
+ );
PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ subProgressPop();
if(keyPair == null) {
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// add subkey binding signature (making this a sub rather than master key)
@@ -577,9 +655,11 @@ public class PgpKeyOperation {
sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
}
+ subProgressPop();
// 6. If requested, change passphrase
if (saveParcel.mNewPassphrase != null) {
+ progress(R.string.progress_modify_passphrase, 90);
log.add(LogLevel.INFO, LogType.MSG_MF_PASSPHRASE, indent);
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
.get(HashAlgorithmTags.SHA1);
@@ -597,18 +677,19 @@ public class PgpKeyOperation {
// This one must only be thrown by
} catch (IOException e) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_ENCODE, indent+1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (PGPException e) {
Log.e(Constants.TAG, "encountered pgp error while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent+1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (SignatureException e) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SIG, indent+1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ progress(R.string.progress_done, 100);
log.add(LogLevel.OK, LogType.MSG_MF_SUCCESS, indent);
- return new UncachedKeyRing(sKR);
+ return new EditKeyResult(OperationResultParcel.RESULT_OK, log, new UncachedKeyRing(sKR));
}
@@ -735,7 +816,7 @@ public class PgpKeyOperation {
int flags = 0;
//noinspection unchecked
for(PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (!sig.hasSubpackets()) {
+ if (sig.getHashedSubPackets() == null) {
continue;
}
flags |= sig.getHashedSubPackets().getKeyFlags();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
index 434b2bf90..09c28e7c5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -278,11 +278,11 @@ public class PgpSignEncrypt {
}
/* Get keys for signature generation for later usage */
- WrappedSecretKey signingKey = null;
+ CanonicalizedSecretKey signingKey = null;
if (enableSignature) {
- WrappedSecretKeyRing signingKeyRing;
+ CanonicalizedSecretKeyRing signingKeyRing;
try {
- signingKeyRing = mProviderHelper.getWrappedSecretKeyRing(mSignatureMasterKeyId);
+ signingKeyRing = mProviderHelper.getCanonicalizedSecretKeyRing(mSignatureMasterKeyId);
} catch (ProviderHelper.NotFoundException e) {
throw new NoSigningKeyException();
}
@@ -337,9 +337,9 @@ public class PgpSignEncrypt {
// Asymmetric encryption
for (long id : mEncryptionMasterKeyIds) {
try {
- WrappedPublicKeyRing keyRing = mProviderHelper.getWrappedPublicKeyRing(
+ CanonicalizedPublicKeyRing keyRing = mProviderHelper.getCanonicalizedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(id));
- WrappedPublicKey key = keyRing.getEncryptionSubKey();
+ CanonicalizedPublicKey key = keyRing.getEncryptionSubKey();
cPk.addMethod(key.getPubKeyEncryptionGenerator());
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "key not found!", e);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 308375a1d..d29f19d67 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -1,7 +1,6 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.bcpg.S2K;
import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPKeyFlags;
@@ -14,28 +13,25 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
-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.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
-import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Set;
import java.util.TreeSet;
-import java.util.Vector;
/** Wrapper around PGPKeyRing class, to be constructed from bytes.
*
@@ -49,7 +45,7 @@ import java.util.Vector;
* treated equally for most purposes in UI code. It is up to the programmer to
* take care of the differences.
*
- * @see org.sufficientlysecure.keychain.pgp.WrappedKeyRing
+ * @see CanonicalizedKeyRing
* @see org.sufficientlysecure.keychain.pgp.UncachedPublicKey
* @see org.sufficientlysecure.keychain.pgp.UncachedSecretKey
*
@@ -59,18 +55,10 @@ public class UncachedKeyRing {
final PGPKeyRing mRing;
final boolean mIsSecret;
- final boolean mIsCanonicalized;
UncachedKeyRing(PGPKeyRing ring) {
mRing = ring;
mIsSecret = ring instanceof PGPSecretKeyRing;
- mIsCanonicalized = false;
- }
-
- private UncachedKeyRing(PGPKeyRing ring, boolean canonicalized) {
- mRing = ring;
- mIsSecret = ring instanceof PGPSecretKeyRing;
- mIsCanonicalized = canonicalized;
}
public long getMasterKeyId() {
@@ -89,7 +77,7 @@ public class UncachedKeyRing {
final Iterator<PGPPublicKey> it = mRing.getPublicKeys();
return new Iterator<UncachedPublicKey>() {
public void remove() {
- it.remove();
+ throw new UnsupportedOperationException();
}
public UncachedPublicKey next() {
return new UncachedPublicKey(it.next());
@@ -105,10 +93,6 @@ public class UncachedKeyRing {
return mIsSecret;
}
- public boolean isCanonicalized() {
- return mIsCanonicalized;
- }
-
public byte[] getEncoded() throws IOException {
return mRing.getEncoded();
}
@@ -119,43 +103,86 @@ public class UncachedKeyRing {
public static UncachedKeyRing decodeFromData(byte[] data)
throws PgpGeneralException, IOException {
- BufferedInputStream bufferedInput =
- new BufferedInputStream(new ByteArrayInputStream(data));
- 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 && obj instanceof PGPKeyRing) {
- return new UncachedKeyRing((PGPKeyRing) obj);
- } else {
- throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
- }
- } else {
+
+ Iterator<UncachedKeyRing> parsed = fromStream(new ByteArrayInputStream(data));
+
+ if ( ! parsed.hasNext()) {
throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
}
+
+ UncachedKeyRing ring = parsed.next();
+
+ if (parsed.hasNext()) {
+ throw new PgpGeneralException("Expected single keyring in stream, found at least two");
+ }
+
+ return ring;
+
}
- public static List<UncachedKeyRing> fromStream(InputStream stream)
- throws PgpGeneralException, IOException {
+ public static Iterator<UncachedKeyRing> fromStream(final InputStream stream) throws IOException {
- PGPObjectFactory objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(stream));
+ return new Iterator<UncachedKeyRing>() {
- List<UncachedKeyRing> result = new Vector<UncachedKeyRing>();
+ UncachedKeyRing mNext = null;
+ PGPObjectFactory mObjectFactory = null;
- // go through all objects in this block
- Object obj;
- while ((obj = objectFactory.nextObject()) != null) {
- Log.d(Constants.TAG, "Found class: " + obj.getClass());
+ private void cacheNext() {
+ if (mNext != null) {
+ return;
+ }
+
+ try {
+ while(stream.available() > 0) {
+ // if there are no objects left from the last factory, create a new one
+ if (mObjectFactory == null) {
+ mObjectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(stream));
+ }
+
+ // go through all objects in this block
+ Object obj;
+ while ((obj = mObjectFactory.nextObject()) != null) {
+ Log.d(Constants.TAG, "Found class: " + obj.getClass());
+ if (!(obj instanceof PGPKeyRing)) {
+ Log.i(Constants.TAG,
+ "Skipping object of bad type " + obj.getClass().getName() + " in stream");
+ // skip object
+ continue;
+ }
+ mNext = new UncachedKeyRing((PGPKeyRing) obj);
+ return;
+ }
+ // if we are past the while loop, that means the objectFactory had no next
+ mObjectFactory = null;
+ }
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException while processing stream", e);
+ }
- if (obj instanceof PGPKeyRing) {
- result.add(new UncachedKeyRing((PGPKeyRing) obj));
- } else {
- Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!");
}
- }
- return result;
+
+ @Override
+ public boolean hasNext() {
+ cacheNext();
+ return mNext != null;
+ }
+
+ @Override
+ public UncachedKeyRing next() {
+ try {
+ cacheNext();
+ return mNext;
+ } finally {
+ mNext = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+
}
public void encodeArmored(OutputStream out, String version) throws IOException {
@@ -165,27 +192,6 @@ public class UncachedKeyRing {
aos.close();
}
- public HashSet<Long> getAvailableSubkeys() {
- if(!isSecret()) {
- throw new RuntimeException("Tried to find available subkeys from non-secret keys. " +
- "This is a programming error and should never happen!");
- }
-
- HashSet<Long> result = new HashSet<Long>();
- // then, mark exactly the keys we have available
- for (PGPSecretKey sub : new IterableIterator<PGPSecretKey>(
- ((PGPSecretKeyRing) mRing).getSecretKeys())) {
- S2K s2k = sub.getS2K();
- // add key, except if the private key has been stripped (GNU extension)
- if(s2k == null || (s2k.getProtectionMode() != S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY)) {
- result.add(sub.getKeyID());
- } else {
- Log.d(Constants.TAG, "S2K GNU extension!, mode: " + s2k.getProtectionMode());
- }
- }
- return result;
- }
-
/** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be
* applied to public keyrings only.
*
@@ -195,7 +201,7 @@ public class UncachedKeyRing {
* - Remove all certificates flagged as "local"
* - Remove all certificates which are superseded by a newer one on the same target,
* including revocations with later re-certifications.
- * - Remove all certificates of unknown type:
+ * - Remove all certificates in other positions if not of known type:
* - key revocation signatures on the master key
* - subkey binding signatures for subkeys
* - certifications and certification revocations for user ids
@@ -210,7 +216,7 @@ public class UncachedKeyRing {
*
*/
@SuppressWarnings("ConstantConditions")
- public UncachedKeyRing canonicalize(OperationLog log, int indent) {
+ public CanonicalizedKeyRing canonicalize(OperationLog log, int indent) {
log.add(LogLevel.START, isSecret() ? LogType.MSG_KC_SECRET : LogType.MSG_KC_PUBLIC,
indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));
@@ -292,14 +298,14 @@ public class UncachedKeyRing {
revocation = zert;
// more revocations? at least one is superfluous, then.
} else if (revocation.getCreationTime().before(zert.getCreationTime())) {
+ log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
modified = PGPPublicKey.removeCertification(modified, revocation);
redundantCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
revocation = zert;
} else {
+ log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
redundantCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
}
}
@@ -323,20 +329,21 @@ public class UncachedKeyRing {
indent, "0x" + Integer.toString(zert.getSignatureType(), 16));
modified = PGPPublicKey.removeCertification(modified, userId, zert);
badCerts += 1;
+ continue;
}
if (cert.getCreationTime().after(now)) {
// Creation date in the future? No way!
- log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, indent);
- modified = PGPPublicKey.removeCertification(modified, zert);
+ log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_TIME, indent);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
badCerts += 1;
continue;
}
if (cert.isLocal()) {
// Creation date in the future? No way!
- log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, indent);
- modified = PGPPublicKey.removeCertification(modified, zert);
+ log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_LOCAL, indent);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
badCerts += 1;
continue;
}
@@ -379,35 +386,35 @@ public class UncachedKeyRing {
if (selfCert == null) {
selfCert = zert;
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
- modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
+ redundantCerts += 1;
selfCert = zert;
} else {
- modified = PGPPublicKey.removeCertification(modified, userId, zert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
+ redundantCerts += 1;
}
// If there is a revocation certificate, and it's older than this, drop it
if (revocation != null
&& revocation.getCreationTime().before(selfCert.getCreationTime())) {
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
+ indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, revocation);
revocation = null;
redundantCerts += 1;
- log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
- indent, userId);
}
break;
case PGPSignature.CERTIFICATION_REVOCATION:
// If this is older than the (latest) self cert, drop it
if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) {
- modified = PGPPublicKey.removeCertification(modified, userId, zert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
+ redundantCerts += 1;
continue;
}
// first revocation? remember it.
@@ -415,16 +422,16 @@ public class UncachedKeyRing {
revocation = zert;
// more revocations? at least one is superfluous, then.
} else if (revocation.getCreationTime().before(cert.getCreationTime())) {
- modified = PGPPublicKey.removeCertification(modified, userId, revocation);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, revocation);
+ redundantCerts += 1;
revocation = zert;
} else {
- modified = PGPPublicKey.removeCertification(modified, userId, zert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
+ redundantCerts += 1;
}
break;
@@ -434,9 +441,9 @@ public class UncachedKeyRing {
// If no valid certificate (if only a revocation) remains, drop it
if (selfCert == null && revocation == null) {
- modified = PGPPublicKey.removeCertification(modified, userId);
log.add(LogLevel.ERROR, LogType.MSG_KC_UID_REMOVE,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId);
}
}
@@ -515,14 +522,17 @@ public class UncachedKeyRing {
continue;
}
- if (zert.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
+ // if this certificate says it allows signing for the key
+ if (zert.getHashedSubPackets() != null &&
+ zert.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
+
int flags = ((KeyFlags) zert.getHashedSubPackets()
.getSubpacket(SignatureSubpacketTags.KEY_FLAGS)).getFlags();
- // If this subkey is allowed to sign data,
if ((flags & PGPKeyFlags.CAN_SIGN) == PGPKeyFlags.CAN_SIGN) {
+ boolean ok = false;
+ // it MUST have an embedded primary key binding signature
try {
PGPSignatureList list = zert.getUnhashedSubPackets().getEmbeddedSignatures();
- boolean ok = false;
for (int i = 0; i < list.size(); i++) {
WrappedSignature subsig = new WrappedSignature(list.get(i));
if (subsig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
@@ -536,17 +546,19 @@ public class UncachedKeyRing {
}
}
}
- if (!ok) {
- log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_NONE, indent);
- badCerts += 1;
- continue;
- }
} catch (Exception e) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD_ERR, indent);
badCerts += 1;
continue;
}
+ // if it doesn't, get rid of this!
+ if (!ok) {
+ log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_NONE, indent);
+ badCerts += 1;
+ continue;
+ }
}
+
}
// if we already have a cert, and this one is not newer: skip it
@@ -559,6 +571,8 @@ public class UncachedKeyRing {
selfCert = zert;
// if this is newer than a possibly existing revocation, drop that one
if (revocation != null && selfCert.getCreationTime().after(revocation.getCreationTime())) {
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_REVOKE_DUP, indent);
+ redundantCerts += 1;
revocation = null;
}
@@ -592,7 +606,7 @@ public class UncachedKeyRing {
// it is not properly bound? error!
if (selfCert == null) {
- ring = replacePublicKey(ring, modified);
+ ring = removeSubKey(ring, key);
log.add(LogLevel.ERROR, LogType.MSG_KC_SUB_NO_CERT,
indent, PgpKeyHelper.convertKeyIdToHex(key.getKeyID()));
@@ -625,7 +639,8 @@ public class UncachedKeyRing {
log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS, indent);
}
- return new UncachedKeyRing(ring, true);
+ return isSecret() ? new CanonicalizedSecretKeyRing((PGPSecretKeyRing) ring, 1)
+ : new CanonicalizedPublicKeyRing((PGPPublicKeyRing) ring, 0);
}
/** This operation merges information from a different keyring, returning a combined
@@ -660,7 +675,7 @@ public class UncachedKeyRing {
return left.length - right.length;
}
// compare byte-by-byte
- for (int i = 0; i < left.length && i < right.length; i++) {
+ for (int i = 0; i < left.length; i++) {
if (left[i] != right[i]) {
return (left[i] & 0xff) - (right[i] & 0xff);
}
@@ -688,7 +703,14 @@ public class UncachedKeyRing {
final PGPPublicKey resultKey = result.getPublicKey(key.getKeyID());
if (resultKey == null) {
log.add(LogLevel.DEBUG, LogType.MSG_MG_NEW_SUBKEY, indent);
- result = replacePublicKey(result, key);
+ // special case: if both rings are secret, copy over the secret key
+ if (isSecret() && other.isSecret()) {
+ PGPSecretKey sKey = ((PGPSecretKeyRing) candidate).getSecretKey(key.getKeyID());
+ result = PGPSecretKeyRing.insertSecretKey((PGPSecretKeyRing) result, sKey);
+ } else {
+ // otherwise, just insert the public key
+ result = replacePublicKey(result, key);
+ }
continue;
}
@@ -696,17 +718,7 @@ public class UncachedKeyRing {
PGPPublicKey modified = resultKey;
// Iterate certifications
- for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getSignatures())) {
- int type = cert.getSignatureType();
- // Disregard certifications on user ids, we will deal with those later
- if (type == PGPSignature.NO_CERTIFICATION
- || type == PGPSignature.DEFAULT_CERTIFICATION
- || type == PGPSignature.CASUAL_CERTIFICATION
- || type == PGPSignature.POSITIVE_CERTIFICATION
- || type == PGPSignature.CERTIFICATION_REVOCATION) {
- continue;
- }
-
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getKeySignatures())) {
// Don't merge foreign stuff into secret keys
if (cert.getKeyID() != masterKeyId && isSecret()) {
continue;
@@ -770,19 +782,20 @@ public class UncachedKeyRing {
}
- public UncachedKeyRing extractPublicKeyRing() {
+ public UncachedKeyRing extractPublicKeyRing() throws IOException {
if(!isSecret()) {
throw new RuntimeException("Tried to extract public keyring from non-secret keyring. " +
"This is a programming error and should never happen!");
}
- ArrayList<PGPPublicKey> keys = new ArrayList();
Iterator<PGPPublicKey> it = mRing.getPublicKeys();
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(2048);
while (it.hasNext()) {
- keys.add(it.next());
+ stream.write(it.next().getEncoded());
}
- return new UncachedKeyRing(new PGPPublicKeyRing(keys));
+ return new UncachedKeyRing(
+ new PGPPublicKeyRing(stream.toByteArray(), new JcaKeyFingerprintCalculator()));
}
/** This method replaces a public key in a keyring.
@@ -806,4 +819,20 @@ public class UncachedKeyRing {
return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
+ /** This method removes a subkey in a keyring.
+ *
+ * This method essentially wraps PGP*KeyRing.remove*Key, where the keyring may be of either
+ * the secret or public subclass.
+ *
+ * @return the resulting PGPKeyRing of the same type as the input
+ */
+ private static PGPKeyRing removeSubKey(PGPKeyRing ring, PGPPublicKey key) {
+ if (ring instanceof PGPPublicKeyRing) {
+ return PGPPublicKeyRing.removePublicKey((PGPPublicKeyRing) ring, key);
+ } else {
+ PGPSecretKey sKey = ((PGPSecretKeyRing) ring).getSecretKey(key.getKeyID());
+ return PGPSecretKeyRing.removeSecretKey((PGPSecretKeyRing) ring, sKey);
+ }
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
index df19930c4..07fb4fb9e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
@@ -63,13 +63,17 @@ public class WrappedSignature {
}
try {
PGPSignatureList list;
- list = mSig.getHashedSubPackets().getEmbeddedSignatures();
- for(int i = 0; i < list.size(); i++) {
- sigs.add(new WrappedSignature(list.get(i)));
+ if (mSig.getHashedSubPackets() != null) {
+ list = mSig.getHashedSubPackets().getEmbeddedSignatures();
+ for (int i = 0; i < list.size(); i++) {
+ sigs.add(new WrappedSignature(list.get(i)));
+ }
}
- list = mSig.getUnhashedSubPackets().getEmbeddedSignatures();
- for(int i = 0; i < list.size(); i++) {
- sigs.add(new WrappedSignature(list.get(i)));
+ if (mSig.getUnhashedSubPackets() != null) {
+ list = mSig.getUnhashedSubPackets().getEmbeddedSignatures();
+ for (int i = 0; i < list.size(); i++) {
+ sigs.add(new WrappedSignature(list.get(i)));
+ }
}
} catch (PGPException e) {
// no matter
@@ -97,6 +101,9 @@ public class WrappedSignature {
if(!isRevocation()) {
throw new PgpGeneralException("Not a revocation signature.");
}
+ if (mSig.getHashedSubPackets() == null) {
+ return null;
+ }
SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket(
SignatureSubpacketTags.REVOCATION_REASON);
// For some reason, this is missing in SignatureSubpacketInputStream:146
@@ -106,7 +113,7 @@ public class WrappedSignature {
return ((RevocationReason) p).getRevocationDescription();
}
- public void init(WrappedPublicKey key) throws PgpGeneralException {
+ public void init(CanonicalizedPublicKey key) throws PgpGeneralException {
init(key.getPublicKey());
}
@@ -184,7 +191,7 @@ public class WrappedSignature {
public boolean verifySignature(UncachedPublicKey key, String uid) throws PgpGeneralException {
return verifySignature(key.getPublicKey(), uid);
}
- public boolean verifySignature(WrappedPublicKey key, String uid) throws PgpGeneralException {
+ public boolean verifySignature(CanonicalizedPublicKey key, String uid) throws PgpGeneralException {
return verifySignature(key.getPublicKey(), uid);
}
@@ -205,7 +212,7 @@ public class WrappedSignature {
}
public boolean isLocal() {
- if (!mSig.hasSubpackets()
+ if (mSig.getHashedSubPackets() == null
|| !mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.EXPORTABLE)) {
return false;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
index 34de0024d..aa0207a6a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
@@ -1,5 +1,6 @@
package org.sufficientlysecure.keychain.provider;
+import android.database.Cursor;
import android.net.Uri;
import org.sufficientlysecure.keychain.Constants;
@@ -33,6 +34,7 @@ public class CachedPublicKeyRing extends KeyRing {
mUri = uri;
}
+ @Override
public long getMasterKeyId() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
@@ -59,10 +61,21 @@ public class CachedPublicKeyRing extends KeyRing {
return getMasterKeyId();
}
+ public byte[] getFingerprint() throws PgpGeneralException {
+ try {
+ Object data = mProviderHelper.getGenericData(mUri,
+ KeychainContract.KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+ return (byte[]) data;
+ } catch (ProviderHelper.NotFoundException e) {
+ throw new PgpGeneralException(e);
+ }
+ }
+
+ @Override
public String getPrimaryUserId() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.USER_ID,
ProviderHelper.FIELD_TYPE_STRING);
return (String) data;
} catch(ProviderHelper.NotFoundException e) {
@@ -74,10 +87,11 @@ public class CachedPublicKeyRing extends KeyRing {
return getPrimaryUserId();
}
+ @Override
public boolean isRevoked() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.IS_REVOKED,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@@ -85,10 +99,11 @@ public class CachedPublicKeyRing extends KeyRing {
}
}
+ @Override
public boolean canCertify() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.CAN_CERTIFY,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@@ -96,21 +111,32 @@ public class CachedPublicKeyRing extends KeyRing {
}
}
+ @Override
public long getEncryptId() throws PgpGeneralException {
try {
- Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
- ProviderHelper.FIELD_TYPE_INTEGER);
- return (Long) data;
- } catch(ProviderHelper.NotFoundException e) {
+ Cursor subkeys = getSubkeys();
+ if (subkeys != null) {
+ try {
+ while (subkeys.moveToNext()) {
+ if (subkeys.getInt(subkeys.getColumnIndexOrThrow(KeychainContract.Keys.CAN_ENCRYPT)) != 0) {
+ return subkeys.getLong(subkeys.getColumnIndexOrThrow(KeychainContract.Keys.KEY_ID));
+ }
+ }
+ } finally {
+ subkeys.close();
+ }
+ }
+ } catch(Exception e) {
throw new PgpGeneralException(e);
}
+ throw new PgpGeneralException("No encrypt key found");
}
+ @Override
public boolean hasEncrypt() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.HAS_ENCRYPT,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@@ -118,21 +144,32 @@ public class CachedPublicKeyRing extends KeyRing {
}
}
+ @Override
public long getSignId() throws PgpGeneralException {
try {
- Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
- ProviderHelper.FIELD_TYPE_INTEGER);
- return (Long) data;
- } catch(ProviderHelper.NotFoundException e) {
+ Cursor subkeys = getSubkeys();
+ if (subkeys != null) {
+ try {
+ while (subkeys.moveToNext()) {
+ if (subkeys.getInt(subkeys.getColumnIndexOrThrow(KeychainContract.Keys.CAN_SIGN)) != 0) {
+ return subkeys.getLong(subkeys.getColumnIndexOrThrow(KeychainContract.Keys.KEY_ID));
+ }
+ }
+ } finally {
+ subkeys.close();
+ }
+ }
+ } catch(Exception e) {
throw new PgpGeneralException(e);
}
+ throw new PgpGeneralException("No sign key found");
}
+ @Override
public boolean hasSign() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.HAS_SIGN,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
@@ -140,10 +177,11 @@ public class CachedPublicKeyRing extends KeyRing {
}
}
+ @Override
public int getVerified() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.VERIFIED,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Integer) data;
} catch(ProviderHelper.NotFoundException e) {
@@ -154,12 +192,16 @@ public class CachedPublicKeyRing extends KeyRing {
public boolean hasAnySecret() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
- KeychainContract.KeyRings.MASTER_KEY_ID,
+ KeychainContract.KeyRings.HAS_ANY_SECRET,
ProviderHelper.FIELD_TYPE_INTEGER);
return (Long) data > 0;
} catch(ProviderHelper.NotFoundException e) {
throw new PgpGeneralException(e);
}
+ }
+ private Cursor getSubkeys() throws PgpGeneralException {
+ Uri keysUri = KeychainContract.Keys.buildKeysUri(Long.toString(extractOrGetMasterKeyId()));
+ return mProviderHelper.getContentResolver().query(keysUri, null, null, null, null);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 2d524f5b0..aa85577e0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -28,10 +28,12 @@ import android.os.RemoteException;
import android.support.v4.util.LongSparseArray;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.NullProgressable;
import org.sufficientlysecure.keychain.pgp.Progressable;
-import org.sufficientlysecure.keychain.pgp.WrappedPublicKey;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
@@ -39,8 +41,6 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
-import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
@@ -180,7 +180,7 @@ public class ProviderHelper {
return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types);
}
- private LongSparseArray<WrappedPublicKey> getTrustedMasterKeys() {
+ private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] {
KeyRings.MASTER_KEY_ID,
// we pick from cache only information that is not easily available from keyrings
@@ -190,16 +190,15 @@ public class ProviderHelper {
}, KeyRings.HAS_ANY_SECRET + " = 1", null, null);
try {
- LongSparseArray<WrappedPublicKey> result = new LongSparseArray<WrappedPublicKey>();
+ LongSparseArray<CanonicalizedPublicKey> result = new LongSparseArray<CanonicalizedPublicKey>();
if (cursor != null && cursor.moveToFirst()) do {
long masterKeyId = cursor.getLong(0);
- boolean hasAnySecret = cursor.getInt(1) > 0;
int verified = cursor.getInt(2);
byte[] blob = cursor.getBlob(3);
if (blob != null) {
result.put(masterKeyId,
- new WrappedPublicKeyRing(blob, hasAnySecret, verified).getPublicKey());
+ new CanonicalizedPublicKeyRing(blob, verified).getPublicKey());
}
} while (cursor.moveToNext());
@@ -217,23 +216,23 @@ public class ProviderHelper {
return new CachedPublicKeyRing(this, queryUri);
}
- public WrappedPublicKeyRing getWrappedPublicKeyRing(long id) throws NotFoundException {
- return (WrappedPublicKeyRing) getWrappedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), false);
+ public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long id) throws NotFoundException {
+ return (CanonicalizedPublicKeyRing) getCanonicalizedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), false);
}
- public WrappedPublicKeyRing getWrappedPublicKeyRing(Uri queryUri) throws NotFoundException {
- return (WrappedPublicKeyRing) getWrappedKeyRing(queryUri, false);
+ public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(Uri queryUri) throws NotFoundException {
+ return (CanonicalizedPublicKeyRing) getCanonicalizedKeyRing(queryUri, false);
}
- public WrappedSecretKeyRing getWrappedSecretKeyRing(long id) throws NotFoundException {
- return (WrappedSecretKeyRing) getWrappedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), true);
+ public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long id) throws NotFoundException {
+ return (CanonicalizedSecretKeyRing) getCanonicalizedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), true);
}
- public WrappedSecretKeyRing getWrappedSecretKeyRing(Uri queryUri) throws NotFoundException {
- return (WrappedSecretKeyRing) getWrappedKeyRing(queryUri, true);
+ public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(Uri queryUri) throws NotFoundException {
+ return (CanonicalizedSecretKeyRing) getCanonicalizedKeyRing(queryUri, true);
}
- private KeyRing getWrappedKeyRing(Uri queryUri, boolean secret) throws NotFoundException {
+ private KeyRing getCanonicalizedKeyRing(Uri queryUri, boolean secret) throws NotFoundException {
Cursor cursor = mContentResolver.query(queryUri,
new String[]{
// we pick from cache only information that is not easily available from keyrings
@@ -252,8 +251,8 @@ public class ProviderHelper {
throw new NotFoundException("Secret key not available!");
}
return secret
- ? new WrappedSecretKeyRing(blob, true, verified)
- : new WrappedPublicKeyRing(blob, hasAnySecret, verified);
+ ? new CanonicalizedSecretKeyRing(blob, true, verified)
+ : new CanonicalizedPublicKeyRing(blob, verified);
} else {
throw new NotFoundException("Key not found!");
}
@@ -271,16 +270,8 @@ public class ProviderHelper {
* and need to be saved externally to be preserved past the operation.
*/
@SuppressWarnings("unchecked")
- private int internalSavePublicKeyRing(UncachedKeyRing keyRing,
- Progressable progress, boolean selfCertsAreTrusted) {
- if (keyRing.isSecret()) {
- log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
- return SaveKeyringResult.RESULT_ERROR;
- }
- if (!keyRing.isCanonicalized()) {
- log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
- return SaveKeyringResult.RESULT_ERROR;
- }
+ private int saveCanonicalizedPublicKeyRing(CanonicalizedPublicKeyRing keyRing,
+ Progressable progress, boolean selfCertsAreTrusted) {
// start with ok result
int result = SaveKeyringResult.SAVED_PUBLIC;
@@ -318,7 +309,7 @@ public class ProviderHelper {
{ // insert subkeys
Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId));
int rank = 0;
- for (UncachedPublicKey key : new IterableIterator<UncachedPublicKey>(keyRing.getPublicKeys())) {
+ for (CanonicalizedPublicKey key : keyRing.publicKeyIterator()) {
long keyId = key.getKeyId();
log(LogLevel.DEBUG, keyId == masterKeyId ? LogType.MSG_IP_MASTER : LogType.MSG_IP_SUBKEY,
PgpKeyHelper.convertKeyIdToHex(keyId)
@@ -401,7 +392,7 @@ public class ProviderHelper {
mIndent -= 1;
// get a list of owned secret keys, for verification filtering
- LongSparseArray<WrappedPublicKey> trustedKeys = getTrustedMasterKeys();
+ LongSparseArray<CanonicalizedPublicKey> trustedKeys = getTrustedMasterKeys();
// classify and order user ids. primary are moved to the front, revoked to the back,
// otherwise the order in the keyfile is preserved.
@@ -445,7 +436,7 @@ public class ProviderHelper {
// verify signatures from known private keys
if (trustedKeys.indexOfKey(certId) >= 0) {
- WrappedPublicKey trustedKey = trustedKeys.get(certId);
+ CanonicalizedPublicKey trustedKey = trustedKeys.get(certId);
cert.init(trustedKey);
if (cert.verifySignature(masterKey, userId)) {
item.trustedCerts.add(cert);
@@ -559,28 +550,13 @@ public class ProviderHelper {
/** Saves an UncachedKeyRing of the secret variant into the db.
* This method will fail if no corresponding public keyring is in the database!
*/
- private int internalSaveSecretKeyRing(UncachedKeyRing keyRing) {
-
- if (!keyRing.isSecret()) {
- log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
- return SaveKeyringResult.RESULT_ERROR;
- }
-
- if (!keyRing.isCanonicalized()) {
- log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
- return SaveKeyringResult.RESULT_ERROR;
- }
+ private int saveCanonicalizedSecretKeyRing(CanonicalizedSecretKeyRing keyRing) {
long masterKeyId = keyRing.getMasterKeyId();
log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId));
mIndent += 1;
- try {
- // Canonicalize this key, to assert a number of assumptions made about it.
- keyRing = keyRing.canonicalize(mLog, mIndent);
- if (keyRing == null) {
- return SaveKeyringResult.RESULT_ERROR;
- }
+ try {
// IF this is successful, it's a secret key
int result = SaveKeyringResult.SAVED_SECRET;
@@ -615,8 +591,7 @@ public class ProviderHelper {
log(LogLevel.INFO, LogType.MSG_IS_IMPORTING_SUBKEYS);
mIndent += 1;
Set<Long> available = keyRing.getAvailableSubkeys();
- for (UncachedPublicKey sub :
- new IterableIterator<UncachedPublicKey>(keyRing.getPublicKeys())) {
+ for (UncachedPublicKey sub : keyRing.publicKeyIterator()) {
long id = sub.getKeyId();
if (available.contains(id)) {
int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?",
@@ -667,9 +642,16 @@ public class ProviderHelper {
log(LogLevel.START, LogType.MSG_IP, PgpKeyHelper.convertKeyIdToHex(masterKeyId));
mIndent += 1;
+ if (publicRing.isSecret()) {
+ log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ CanonicalizedPublicKeyRing canPublicRing;
+
// If there is an old keyring, merge it
try {
- UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncachedKeyRing();
+ UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing();
// Merge data from new public ring into the old one
publicRing = oldPublicRing.merge(publicRing, mLog, mIndent);
@@ -680,8 +662,8 @@ public class ProviderHelper {
}
// Canonicalize this keyring, to assert a number of assumptions made about it.
- publicRing = publicRing.canonicalize(mLog, mIndent);
- if (publicRing == null) {
+ canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
+ if (canPublicRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
@@ -695,39 +677,40 @@ public class ProviderHelper {
// Not an issue, just means we are dealing with a new keyring.
// Canonicalize this keyring, to assert a number of assumptions made about it.
- publicRing = publicRing.canonicalize(mLog, mIndent);
- if (publicRing == null) {
+ canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
+ if (canPublicRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
}
// If there is a secret key, merge new data (if any) and save the key for later
- UncachedKeyRing secretRing;
+ CanonicalizedSecretKeyRing canSecretRing;
try {
- secretRing = getWrappedSecretKeyRing(publicRing.getMasterKeyId()).getUncachedKeyRing();
+ UncachedKeyRing secretRing = getCanonicalizedSecretKeyRing(publicRing.getMasterKeyId()).getUncachedKeyRing();
// Merge data from new public ring into secret one
secretRing = secretRing.merge(publicRing, mLog, mIndent);
if (secretRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
- secretRing = secretRing.canonicalize(mLog, mIndent);
- if (secretRing == null) {
+ // This has always been a secret key ring, this is a safe cast
+ canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
+ if (canSecretRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
} catch (NotFoundException e) {
// No secret key available (this is what happens most of the time)
- secretRing = null;
+ canSecretRing = null;
}
- int result = internalSavePublicKeyRing(publicRing, progress, secretRing != null);
+ int result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, canSecretRing != null);
// Save the saved keyring (if any)
- if (secretRing != null) {
+ if (canSecretRing != null) {
progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
- int secretResult = internalSaveSecretKeyRing(secretRing);
+ int secretResult = saveCanonicalizedSecretKeyRing(canSecretRing);
if ((secretResult & SaveKeyringResult.RESULT_ERROR) != SaveKeyringResult.RESULT_ERROR) {
result |= SaveKeyringResult.SAVED_SECRET;
}
@@ -751,9 +734,16 @@ public class ProviderHelper {
log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId));
mIndent += 1;
+ if ( ! secretRing.isSecret()) {
+ log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC);
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
+
+ CanonicalizedSecretKeyRing canSecretRing;
+
// If there is an old secret key, merge it.
try {
- UncachedKeyRing oldSecretRing = getWrappedSecretKeyRing(masterKeyId).getUncachedKeyRing();
+ UncachedKeyRing oldSecretRing = getCanonicalizedSecretKeyRing(masterKeyId).getUncachedKeyRing();
// Merge data from new secret ring into old one
secretRing = secretRing.merge(oldSecretRing, mLog, mIndent);
@@ -764,8 +754,9 @@ public class ProviderHelper {
}
// Canonicalize this keyring, to assert a number of assumptions made about it.
- secretRing = secretRing.canonicalize(mLog, mIndent);
- if (secretRing == null) {
+ // This is a safe cast, because we made sure this is a secret ring above
+ canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
+ if (canSecretRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
@@ -780,8 +771,9 @@ public class ProviderHelper {
// Not an issue, just means we are dealing with a new keyring
// Canonicalize this keyring, to assert a number of assumptions made about it.
- secretRing = secretRing.canonicalize(mLog, mIndent);
- if (secretRing == null) {
+ // This is a safe cast, because we made sure this is a secret ring above
+ canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent);
+ if (canSecretRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
@@ -790,7 +782,7 @@ public class ProviderHelper {
// Merge new data into public keyring as well, if there is any
UncachedKeyRing publicRing;
try {
- UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncachedKeyRing();
+ UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing();
// Merge data from new secret ring into public one
publicRing = oldPublicRing.merge(secretRing, mLog, mIndent);
@@ -798,31 +790,26 @@ public class ProviderHelper {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
- // If nothing changed, never mind
- if (Arrays.hashCode(publicRing.getEncoded())
- == Arrays.hashCode(oldPublicRing.getEncoded())) {
- publicRing = null;
- }
-
} catch (NotFoundException e) {
log(LogLevel.DEBUG, LogType.MSG_IS_PUBRING_GENERATE);
publicRing = secretRing.extractPublicKeyRing();
}
- if (publicRing != null) {
- publicRing = publicRing.canonicalize(mLog, mIndent);
- if (publicRing == null) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
- }
+ CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent);
+ if (canPublicRing == null) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
+ }
- int result = internalSavePublicKeyRing(publicRing, progress, true);
- if ((result & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) {
- return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
- }
+ int result;
+
+ result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true);
+ if ((result & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) {
+ return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
}
progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
- int result = internalSaveSecretKeyRing(secretRing);
+ result = saveCanonicalizedSecretKeyRing(canSecretRing);
+
return new SaveKeyringResult(result, mLog);
} catch (IOException e) {
@@ -1037,4 +1024,8 @@ public class ProviderHelper {
}
}
}
+
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index 64f5e1050..eae217e16 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -457,7 +457,7 @@ public class OpenPgpService extends RemoteService {
try {
// try to find key, throws NotFoundException if not in db!
- mProviderHelper.getWrappedPublicKeyRing(masterKeyId);
+ mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId);
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
index 0b1d521ad..2ba792f9a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
@@ -32,10 +32,11 @@ import android.widget.Button;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.remote.AccountSettings;
-import org.sufficientlysecure.keychain.ui.EditKeyActivityOld;
+import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
import org.sufficientlysecure.keychain.util.AlgorithmNames;
@@ -163,11 +164,11 @@ public class AccountSettingsFragment extends Fragment implements
}
private void createKey() {
- Intent intent = new Intent(getActivity(), EditKeyActivityOld.class);
- intent.setAction(EditKeyActivityOld.ACTION_CREATE_KEY);
- intent.putExtra(EditKeyActivityOld.EXTRA_GENERATE_DEFAULT_KEYS, true);
- // set default user id to account name
- intent.putExtra(EditKeyActivityOld.EXTRA_USER_IDS, mAccSettings.getAccountName());
+ String[] userId = KeyRing.splitUserId(mAccSettings.getAccountName());
+
+ Intent intent = new Intent(getActivity(), CreateKeyActivity.class);
+ intent.putExtra(CreateKeyActivity.EXTRA_NAME, userId[0]);
+ intent.putExtra(CreateKeyActivity.EXTRA_EMAIL, userId[1]);
startActivityForResult(intent, REQUEST_CODE_CREATE_KEY);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 77b207bdc..426b86590 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -31,11 +31,15 @@ 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.keyimport.FileImportCache;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
-import org.sufficientlysecure.keychain.keyimport.Keyserver;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver;
+import org.sufficientlysecure.keychain.keyimport.Keyserver;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
@@ -44,15 +48,13 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
-import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
+import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
+import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -169,7 +171,7 @@ public class KeychainIntentService extends IntentService
// export
public static final String RESULT_EXPORT = "exported";
- public static final String RESULT = "result";
+ public static final String RESULT_IMPORT = "result";
Messenger mMessenger;
@@ -330,39 +332,37 @@ public class KeychainIntentService extends IntentService
/* Operation */
ProviderHelper providerHelper = new ProviderHelper(this);
- PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 50, 100));
- try {
- OperationLog log = new OperationLog();
- UncachedKeyRing ring;
- if (saveParcel.mMasterKeyId != null) {
- String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
- WrappedSecretKeyRing secRing =
- providerHelper.getWrappedSecretKeyRing(saveParcel.mMasterKeyId);
-
- ring = keyOperations.modifySecretKeyRing(secRing, saveParcel,
- passphrase, log, 0);
- } else {
- ring = keyOperations.createSecretKeyRing(saveParcel, log, 0);
- }
+ PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100));
+ EditKeyResult result;
- providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 10, 95, 100));
+ if (saveParcel.mMasterKeyId != null) {
+ String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
+ CanonicalizedSecretKeyRing secRing =
+ providerHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
- // cache new passphrase
- if (saveParcel.mNewPassphrase != null) {
- PassphraseCacheService.addCachedPassphrase(this, ring.getMasterKeyId(),
- saveParcel.mNewPassphrase, ring.getPublicKey().getPrimaryUserIdWithFallback());
- }
- } catch (ProviderHelper.NotFoundException e) {
- sendErrorToHandler(e);
+ result = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
+ } else {
+ result = keyOperations.createSecretKeyRing(saveParcel);
+ }
+
+ UncachedKeyRing ring = result.getRing();
+
+ providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
+
+ // cache new passphrase
+ if (saveParcel.mNewPassphrase != null) {
+ PassphraseCacheService.addCachedPassphrase(this, ring.getMasterKeyId(),
+ saveParcel.mNewPassphrase, ring.getPublicKey().getPrimaryUserIdWithFallback());
}
setProgress(R.string.progress_done, 100, 100);
/* Output */
- sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
+ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
} catch (Exception e) {
sendErrorToHandler(e);
}
+
} else if (ACTION_DELETE_FILE_SECURELY.equals(action)) {
try {
/* Input */
@@ -386,13 +386,21 @@ public class KeychainIntentService extends IntentService
}
} else if (ACTION_IMPORT_KEYRING.equals(action)) {
try {
- List<ParcelableKeyRing> entries = data.getParcelableArrayList(IMPORT_KEY_LIST);
+ List<ParcelableKeyRing> entries;
+ if (data.containsKey(IMPORT_KEY_LIST)) {
+ // get entries from intent
+ entries = data.getParcelableArrayList(IMPORT_KEY_LIST);
+ } else {
+ // get entries from cached file
+ FileImportCache cache = new FileImportCache(this);
+ entries = cache.readCache();
+ }
PgpImportExport pgpImportExport = new PgpImportExport(this, this);
- OperationResults.ImportResult result = pgpImportExport.importKeyRings(entries);
+ ImportKeyResult result = pgpImportExport.importKeyRings(entries);
Bundle resultData = new Bundle();
- resultData.putParcelable(RESULT, result);
+ resultData.putParcelable(RESULT_IMPORT, result);
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
@@ -466,7 +474,7 @@ public class KeychainIntentService extends IntentService
HkpKeyserver server = new HkpKeyserver(keyServer);
ProviderHelper providerHelper = new ProviderHelper(this);
- WrappedPublicKeyRing keyring = providerHelper.getWrappedPublicKeyRing(dataUri);
+ CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
PgpImportExport pgpImportExport = new PgpImportExport(this, null);
boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, keyring);
@@ -515,6 +523,7 @@ public class KeychainIntentService extends IntentService
Intent importIntent = new Intent(this, KeychainIntentService.class);
importIntent.setAction(ACTION_IMPORT_KEYRING);
Bundle importData = new Bundle();
+ // This is not going through binder, nothing to fear of
importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings);
importIntent.putExtra(EXTRA_DATA, importData);
importIntent.putExtra(EXTRA_MESSENGER, mMessenger);
@@ -542,9 +551,9 @@ public class KeychainIntentService extends IntentService
}
ProviderHelper providerHelper = new ProviderHelper(this);
- WrappedPublicKeyRing publicRing = providerHelper.getWrappedPublicKeyRing(pubKeyId);
- WrappedSecretKeyRing secretKeyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId);
- WrappedSecretKey certificationKey = secretKeyRing.getSecretKey();
+ CanonicalizedPublicKeyRing publicRing = providerHelper.getCanonicalizedPublicKeyRing(pubKeyId);
+ CanonicalizedSecretKeyRing secretKeyRing = providerHelper.getCanonicalizedSecretKeyRing(masterKeyId);
+ CanonicalizedSecretKey certificationKey = secretKeyRing.getSecretKey();
if(!certificationKey.unlock(signaturePassphrase)) {
throw new PgpGeneralException("Error extracting key (bad passphrase?)");
}
@@ -622,6 +631,12 @@ public class KeychainIntentService extends IntentService
}
}
+ private void sendMessageToHandler(Integer arg1, OperationResultParcel data) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(OperationResultParcel.EXTRA_RESULT, data);
+ sendMessageToHandler(arg1, null, bundle);
+ }
+
private void sendMessageToHandler(Integer arg1, Bundle data) {
sendMessageToHandler(arg1, null, data);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
index 755827482..0cdbe708e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
@@ -25,12 +25,11 @@ import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
public class KeychainIntentServiceHandler extends Handler {
@@ -102,9 +101,9 @@ public class KeychainIntentServiceHandler extends Handler {
// show error from service
if (data.containsKey(DATA_ERROR)) {
- AppMsg.makeText(mActivity,
+ Notify.showNotify(mActivity,
mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)),
- AppMsg.STYLE_ALERT).show();
+ Notify.Style.ERROR);
}
break;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 89d534df6..c27b3f6da 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -1,10 +1,20 @@
package org.sufficientlysecure.keychain.service;
+import android.app.Activity;
+import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.View;
+
+import com.github.johnpersano.supertoasts.SuperCardToast;
+import com.github.johnpersano.supertoasts.SuperToast;
+import com.github.johnpersano.supertoasts.util.OnClickWrapper;
+import com.github.johnpersano.supertoasts.util.Style;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
+import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
@@ -24,6 +34,9 @@ import java.util.List;
*
*/
public class OperationResultParcel implements Parcelable {
+
+ public static final String EXTRA_RESULT = "operation_result";
+
/** Holds the overall result, the number specifying varying degrees of success. The first bit
* is 0 on overall success, 1 on overall failure. All other bits may be used for more specific
* conditions. */
@@ -70,6 +83,7 @@ public class OperationResultParcel implements Parcelable {
mType = type;
mParameters = parameters;
mIndent = indent;
+ Log.v(Constants.TAG, "log: " + this.toString());
}
public LogEntryParcel(Parcel source) {
@@ -113,6 +127,68 @@ public class OperationResultParcel implements Parcelable {
}
}
+ public SuperCardToast createNotify(final Activity activity) {
+
+ int resultType = getResult();
+
+ String str;
+ int duration, color;
+
+ // Not an overall failure
+ if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {
+
+ if (getLog().containsWarnings()) {
+ duration = 0;
+ color = Style.ORANGE;
+ } else {
+ duration = SuperToast.Duration.LONG;
+ color = Style.GREEN;
+ }
+
+ str = "operation succeeded!";
+ // str = activity.getString(R.string.import_error);
+
+ } else {
+
+ duration = 0;
+ color = Style.RED;
+
+ str = "operation failed";
+ // str = activity.getString(R.string.import_error);
+
+ }
+
+ boolean button = getLog() != null && !getLog().isEmpty();
+ SuperCardToast toast = new SuperCardToast(activity,
+ button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD,
+ Style.getStyle(color, SuperToast.Animations.POPUP));
+ toast.setText(str);
+ toast.setDuration(duration);
+ toast.setIndeterminate(duration == 0);
+ toast.setSwipeToDismiss(true);
+ // If we have a log and it's non-empty, show a View Log button
+ if (button) {
+ toast.setButtonIcon(R.drawable.ic_action_view_as_list,
+ activity.getResources().getString(R.string.view_log));
+ toast.setButtonTextColor(activity.getResources().getColor(R.color.black));
+ toast.setTextColor(activity.getResources().getColor(R.color.black));
+ toast.setOnClickWrapper(new OnClickWrapper("supercardtoast",
+ new SuperToast.OnClickListener() {
+ @Override
+ public void onClick(View view, Parcelable token) {
+ Intent intent = new Intent(
+ activity, LogDisplayActivity.class);
+ intent.putExtra(LogDisplayFragment.EXTRA_RESULT, OperationResultParcel.this);
+ activity.startActivity(intent);
+ }
+ }
+ ));
+ }
+
+ return toast;
+
+ }
+
/** This is an enum of all possible log events.
*
* Element names should generally be prefixed with MSG_XX_ where XX is an
@@ -132,6 +208,8 @@ public class OperationResultParcel implements Parcelable {
*/
public static enum LogType {
+ INTERNAL_ERROR (R.string.internal_error),
+
// import public
MSG_IP(R.string.msg_ip),
MSG_IP_APPLY_BATCH (R.string.msg_ip_apply_batch),
@@ -279,6 +357,7 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_UID_ADD (R.string.msg_mf_uid_add),
MSG_MF_UID_PRIMARY (R.string.msg_mf_uid_primary),
MSG_MF_UID_REVOKE (R.string.msg_mf_uid_revoke),
+ MSG_MF_UID_ERROR_EMPTY (R.string.msg_mf_uid_error_empty),
MSG_MF_UNLOCK_ERROR (R.string.msg_mf_unlock_error),
MSG_MF_UNLOCK (R.string.msg_mf_unlock),
;
@@ -329,12 +408,10 @@ public class OperationResultParcel implements Parcelable {
/// Simple convenience method
public void add(LogLevel level, LogType type, int indent, Object... parameters) {
- Log.d(Constants.TAG, type.toString());
mParcels.add(new OperationResultParcel.LogEntryParcel(level, type, indent, parameters));
}
public void add(LogLevel level, LogType type, int indent) {
- Log.d(Constants.TAG, type.toString());
mParcels.add(new OperationResultParcel.LogEntryParcel(level, type, indent, (Object[]) null));
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
index fd3d4ed00..11829e7b8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
@@ -12,12 +12,13 @@ import com.github.johnpersano.supertoasts.util.OnClickWrapper;
import com.github.johnpersano.supertoasts.util.Style;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
public abstract class OperationResults {
- public static class ImportResult extends OperationResultParcel {
+ public static class ImportKeyResult extends OperationResultParcel {
public final int mNewKeys, mUpdatedKeys, mBadKeys;
@@ -47,15 +48,15 @@ public abstract class OperationResults {
return (mResult & RESULT_FAIL_NOTHING) == RESULT_FAIL_NOTHING;
}
- public ImportResult(Parcel source) {
+ public ImportKeyResult(Parcel source) {
super(source);
mNewKeys = source.readInt();
mUpdatedKeys = source.readInt();
mBadKeys = source.readInt();
}
- public ImportResult(int result, OperationLog log,
- int newKeys, int updatedKeys, int badKeys) {
+ public ImportKeyResult(int result, OperationLog log,
+ int newKeys, int updatedKeys, int badKeys) {
super(result, log);
mNewKeys = newKeys;
mUpdatedKeys = updatedKeys;
@@ -70,17 +71,17 @@ public abstract class OperationResults {
dest.writeInt(mBadKeys);
}
- public static Creator<ImportResult> CREATOR = new Creator<ImportResult>() {
- public ImportResult createFromParcel(final Parcel source) {
- return new ImportResult(source);
+ public static Creator<ImportKeyResult> CREATOR = new Creator<ImportKeyResult>() {
+ public ImportKeyResult createFromParcel(final Parcel source) {
+ return new ImportKeyResult(source);
}
- public ImportResult[] newArray(final int size) {
- return new ImportResult[size];
+ public ImportKeyResult[] newArray(final int size) {
+ return new ImportKeyResult[size];
}
};
- public void displayNotify(final Activity activity) {
+ public SuperCardToast createNotify(final Activity activity) {
int resultType = getResult();
@@ -88,11 +89,11 @@ public abstract class OperationResults {
int duration, color;
// Not an overall failure
- if ((resultType & ImportResult.RESULT_ERROR) == 0) {
+ if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {
String withWarnings;
// Any warnings?
- if ((resultType & ImportResult.RESULT_WITH_WARNINGS) > 0) {
+ if ((resultType & ImportKeyResult.RESULT_WITH_WARNINGS) > 0) {
duration = 0;
color = Style.ORANGE;
withWarnings = activity.getResources().getString(R.string.import_with_warnings);
@@ -106,7 +107,7 @@ public abstract class OperationResults {
if (this.isOkBoth()) {
str = activity.getResources().getQuantityString(
R.plurals.import_keys_added_and_updated_1, mNewKeys, mNewKeys);
- str += activity.getResources().getQuantityString(
+ str += " "+ activity.getResources().getQuantityString(
R.plurals.import_keys_added_and_updated_2, mUpdatedKeys, mUpdatedKeys, withWarnings);
} else if (isOkUpdated()) {
str = activity.getResources().getQuantityString(
@@ -142,7 +143,7 @@ public abstract class OperationResults {
// If we have a log and it's non-empty, show a View Log button
if (button) {
toast.setButtonIcon(R.drawable.ic_action_view_as_list,
- activity.getResources().getString(R.string.import_view_log));
+ activity.getResources().getString(R.string.view_log));
toast.setButtonTextColor(activity.getResources().getColor(R.color.black));
toast.setTextColor(activity.getResources().getColor(R.color.black));
toast.setOnClickWrapper(new OnClickWrapper("supercardtoast",
@@ -151,18 +152,59 @@ public abstract class OperationResults {
public void onClick(View view, Parcelable token) {
Intent intent = new Intent(
activity, LogDisplayActivity.class);
- intent.putExtra(LogDisplayFragment.EXTRA_RESULT, ImportResult.this);
+ intent.putExtra(LogDisplayFragment.EXTRA_RESULT, ImportKeyResult.this);
activity.startActivity(intent);
}
}
));
}
- toast.show();
+ return toast;
+
+ }
+
+ }
+
+ public static class EditKeyResult extends OperationResultParcel {
+
+ private transient UncachedKeyRing mRing;
+ public final Long mRingMasterKeyId;
+
+ public EditKeyResult(int result, OperationLog log,
+ UncachedKeyRing ring) {
+ super(result, log);
+ mRing = ring;
+ mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : null;
+ }
+
+ public UncachedKeyRing getRing() {
+ return mRing;
+ }
+
+ public EditKeyResult(Parcel source) {
+ super(source);
+ mRingMasterKeyId = source.readLong();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeLong(mRingMasterKeyId);
}
+ public static Creator<EditKeyResult> CREATOR = new Creator<EditKeyResult>() {
+ public EditKeyResult createFromParcel(final Parcel source) {
+ return new EditKeyResult(source);
+ }
+
+ public EditKeyResult[] newArray(final int size) {
+ return new EditKeyResult[size];
+ }
+ };
+
}
+
public static class SaveKeyringResult extends OperationResultParcel {
public SaveKeyringResult(int result, OperationLog log) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index 774b9a0df..97d92dbf7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -18,9 +18,9 @@
package org.sufficientlysecure.keychain.service;
import android.app.AlarmManager;
+import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
-import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -42,7 +42,7 @@ import org.spongycastle.bcpg.S2K;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -71,7 +71,7 @@ public class PassphraseCacheService extends Service {
public static final String EXTRA_KEY_ID = "key_id";
public static final String EXTRA_PASSPHRASE = "passphrase";
public static final String EXTRA_MESSENGER = "messenger";
- public static final String EXTRA_USERID = "userid";
+ public static final String EXTRA_USER_ID = "user_id";
private static final int REQUEST_ID = 0;
private static final long DEFAULT_TTL = 15;
@@ -103,7 +103,7 @@ public class PassphraseCacheService extends Service {
intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassphraseCacheTtl());
intent.putExtra(EXTRA_PASSPHRASE, passphrase);
intent.putExtra(EXTRA_KEY_ID, keyId);
- intent.putExtra(EXTRA_USERID, primaryUserId);
+ intent.putExtra(EXTRA_USER_ID, primaryUserId);
context.startService(intent);
}
@@ -185,7 +185,7 @@ public class PassphraseCacheService extends Service {
// try to get master key id which is used as an identifier for cached passphrases
try {
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + keyId);
- WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing(
+ CanonicalizedSecretKeyRing key = new ProviderHelper(this).getCanonicalizedSecretKeyRing(
KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId));
// no passphrase needed? just add empty string and return it, then
if (!key.hasPassphrase()) {
@@ -209,18 +209,18 @@ public class PassphraseCacheService extends Service {
// get cached passphrase
CachedPassphrase cachedPassphrase = mPassphraseCache.get(keyId);
if (cachedPassphrase == null) {
- Log.d(Constants.TAG, "PassphraseCacheService Passphrase not (yet) cached, returning null");
+ Log.d(Constants.TAG, "PassphraseCacheService: Passphrase not (yet) cached, returning null");
// not really an error, just means the passphrase is not cached but not empty either
return null;
}
// set it again to reset the cache life cycle
- Log.d(Constants.TAG, "PassphraseCacheService Cache passphrase again when getting it!");
+ Log.d(Constants.TAG, "PassphraseCacheService: Cache passphrase again when getting it!");
addCachedPassphrase(this, keyId, cachedPassphrase.getPassphrase(), cachedPassphrase.getPrimaryUserID());
return cachedPassphrase.getPassphrase();
} catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "PassphraseCacheService Passphrase for unknown key was requested!");
+ Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
return null;
}
}
@@ -237,7 +237,7 @@ public class PassphraseCacheService extends Service {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- Log.d(Constants.TAG, "PassphraseCacheService Received broadcast...");
+ Log.d(Constants.TAG, "PassphraseCacheService: Received broadcast...");
if (action.equals(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE)) {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
@@ -262,10 +262,8 @@ public class PassphraseCacheService extends Service {
private static PendingIntent buildIntent(Context context, long keyId) {
Intent intent = new Intent(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE);
intent.putExtra(EXTRA_KEY_ID, keyId);
- PendingIntent sender = PendingIntent.getBroadcast(context, REQUEST_ID, intent,
+ return PendingIntent.getBroadcast(context, REQUEST_ID, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
-
- return sender;
}
/**
@@ -284,11 +282,12 @@ public class PassphraseCacheService extends Service {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE);
- String primaryUserID = intent.getStringExtra(EXTRA_USERID);
+ String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);
Log.d(Constants.TAG,
- "PassphraseCacheService Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: "
- + keyId + ", ttl: " + ttl + ", usrId: " + primaryUserID);
+ "PassphraseCacheService: Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: "
+ + keyId + ", ttl: " + ttl + ", usrId: " + primaryUserID
+ );
// add keyId, passphrase and primary user id to memory
mPassphraseCache.put(keyId, new CachedPassphrase(passphrase, primaryUserID));
@@ -300,8 +299,7 @@ public class PassphraseCacheService extends Service {
am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, keyId));
}
- updateNotifications();
-
+ updateService();
} else if (ACTION_PASSPHRASE_CACHE_GET.equals(intent.getAction())) {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
@@ -315,21 +313,21 @@ public class PassphraseCacheService extends Service {
try {
messenger.send(msg);
} catch (RemoteException e) {
- Log.e(Constants.TAG, "PassphraseCacheService Sending message failed", e);
+ Log.e(Constants.TAG, "PassphraseCacheService: Sending message failed", e);
}
} else if (ACTION_PASSPHRASE_CACHE_CLEAR.equals(intent.getAction())) {
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// Stop all ttl alarms
- for(int i = 0; i < mPassphraseCache.size(); i++) {
+ for (int i = 0; i < mPassphraseCache.size(); i++) {
am.cancel(buildIntent(this, mPassphraseCache.keyAt(i)));
}
mPassphraseCache.clear();
- updateNotifications();
+ updateService();
} else {
- Log.e(Constants.TAG, "PassphraseCacheService Intent or Intent Action not supported!");
+ Log.e(Constants.TAG, "PassphraseCacheService: Intent or Intent Action not supported!");
}
}
@@ -348,79 +346,74 @@ public class PassphraseCacheService extends Service {
Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!");
- // stop whole service if no cached passphrases remaining
- if (mPassphraseCache.size() == 0) {
- Log.d(Constants.TAG, "PassphraseCacheServic No passphrases remaining in memory, stopping service!");
- stopSelf();
- }
-
- updateNotifications();
+ updateService();
}
- private void updateNotifications() {
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ private void updateService() {
+ if (mPassphraseCache.size() > 0) {
+ startForeground(NOTIFICATION_ID, getNotification());
+ } else {
+ // stop whole service if no cached passphrases remaining
+ Log.d(Constants.TAG, "PassphraseCacheService: No passphrases remaining in memory, stopping service!");
+ stopForeground(true);
+ }
+ }
- if(mPassphraseCache.size() > 0) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+ private Notification getNotification() {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
- builder.setSmallIcon(R.drawable.ic_launcher)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ builder.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.app_name))
- .setContentText(String.format(getString(R.string.passp_cache_notif_n_keys), mPassphraseCache.size()));
+ .setContentText(String.format(getString(R.string.passp_cache_notif_n_keys),
+ mPassphraseCache.size()));
- NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
+ NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
- inboxStyle.setBigContentTitle(getString(R.string.passp_cache_notif_keys));
+ inboxStyle.setBigContentTitle(getString(R.string.passp_cache_notif_keys));
- // Moves events into the big view
- for (int i = 0; i < mPassphraseCache.size(); i++) {
- inboxStyle.addLine(mPassphraseCache.valueAt(i).getPrimaryUserID());
- }
+ // Moves events into the big view
+ for (int i = 0; i < mPassphraseCache.size(); i++) {
+ inboxStyle.addLine(mPassphraseCache.valueAt(i).getPrimaryUserID());
+ }
- // Moves the big view style object into the notification object.
- builder.setStyle(inboxStyle);
+ // Moves the big view style object into the notification object.
+ builder.setStyle(inboxStyle);
- // Add purging action
- Intent intent = new Intent(getApplicationContext(), PassphraseCacheService.class);
- intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
- builder.addAction(
+ // Add purging action
+ Intent intent = new Intent(getApplicationContext(), PassphraseCacheService.class);
+ intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
+ builder.addAction(
R.drawable.abc_ic_clear_normal,
getString(R.string.passp_cache_notif_clear),
PendingIntent.getService(
- getApplicationContext(),
- 0,
- intent,
- PendingIntent.FLAG_UPDATE_CURRENT
+ getApplicationContext(),
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
)
- );
-
- notificationManager.notify(NOTIFICATION_ID, builder.build());
- } else { // Fallback, since expandable notifications weren't available back then
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
-
- builder.setSmallIcon(R.drawable.ic_launcher)
- .setContentTitle(String.format(getString(R.string.passp_cache_notif_n_keys, mPassphraseCache.size())))
+ );
+ } else {
+ // Fallback, since expandable notifications weren't available back then
+ builder.setSmallIcon(R.drawable.ic_launcher)
+ .setContentTitle(String.format(getString(R.string.passp_cache_notif_n_keys,
+ mPassphraseCache.size())))
.setContentText(getString(R.string.passp_cache_notif_click_to_clear));
- Intent intent = new Intent(getApplicationContext(), PassphraseCacheService.class);
- intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
+ Intent intent = new Intent(getApplicationContext(), PassphraseCacheService.class);
+ intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
- builder.setContentIntent(
+ builder.setContentIntent(
PendingIntent.getService(
- getApplicationContext(),
- 0,
- intent,
- PendingIntent.FLAG_UPDATE_CURRENT
+ getApplicationContext(),
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
)
- );
-
- notificationManager.notify(NOTIFICATION_ID, builder.build());
- }
-
- } else {
- notificationManager.cancel(NOTIFICATION_ID);
+ );
}
+
+ return builder.build();
}
@Override
@@ -463,6 +456,7 @@ public class PassphraseCacheService extends Service {
public String getPrimaryUserID() {
return primaryUserID;
}
+
public String getPassphrase() {
return passphrase;
}
@@ -470,6 +464,7 @@ public class PassphraseCacheService extends Service {
public void setPrimaryUserID(String primaryUserID) {
this.primaryUserID = primaryUserID;
}
+
public void setPassphrase(String passphrase) {
this.passphrase = passphrase;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
index 7ac229b91..467e0c14a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui;
import android.app.ProgressDialog;
import android.content.Intent;
import android.database.Cursor;
+import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -37,12 +38,11 @@ import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
@@ -52,10 +52,12 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.util.ArrayList;
@@ -64,7 +66,8 @@ import java.util.ArrayList;
*/
public class CertifyKeyActivity extends ActionBarActivity implements
SelectSecretKeyLayoutFragment.SelectSecretKeyCallback, LoaderManager.LoaderCallbacks<Cursor> {
- private View mSignButton;
+ private View mCertifyButton;
+ private ImageView mActionCertifyImage;
private CheckBox mUploadKeyCheckbox;
private Spinner mSelectKeyserverSpinner;
@@ -88,10 +91,19 @@ public class CertifyKeyActivity extends ActionBarActivity implements
mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getSupportFragmentManager()
.findFragmentById(R.id.sign_key_select_key_fragment);
+ mSelectKeyserverSpinner = (Spinner) findViewById(R.id.upload_key_keyserver);
+ mUploadKeyCheckbox = (CheckBox) findViewById(R.id.sign_key_upload_checkbox);
+ mCertifyButton = findViewById(R.id.certify_key_certify_button);
+ mActionCertifyImage = (ImageView) findViewById(R.id.certify_key_action_certify_image);
+ mUserIds = (ListView) findViewById(R.id.view_key_user_ids);
+
+ // make certify image gray, like action icons
+ mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
+ PorterDuff.Mode.SRC_IN);
+
mSelectKeyFragment.setCallback(this);
mSelectKeyFragment.setFilterCertify(true);
- mSelectKeyserverSpinner = (Spinner) findViewById(R.id.upload_key_keyserver);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
.getKeyServers()
@@ -99,7 +111,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSelectKeyserverSpinner.setAdapter(adapter);
- mUploadKeyCheckbox = (CheckBox) findViewById(R.id.sign_key_upload_checkbox);
if (!mUploadKeyCheckbox.isChecked()) {
mSelectKeyserverSpinner.setEnabled(false);
} else {
@@ -118,16 +129,17 @@ public class CertifyKeyActivity extends ActionBarActivity implements
}
});
- mSignButton = findViewById(R.id.sign_key_sign_button);
- mSignButton.setOnClickListener(new OnClickListener() {
+ mCertifyButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mPubKeyId != 0) {
if (mMasterKeyId == 0) {
mSelectKeyFragment.setError(getString(R.string.select_key_to_certify));
+ Notify.showNotify(CertifyKeyActivity.this, getString(R.string.select_key_to_certify),
+ Notify.Style.ERROR);
} else {
- initiateSigning();
+ initiateCertifying();
}
}
}
@@ -141,7 +153,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements
}
Log.e(Constants.TAG, "uri: " + mDataUri);
- mUserIds = (ListView) findViewById(R.id.view_key_user_ids);
mUserIdsAdapter = new UserIdsAdapter(this, null, 0, true);
mUserIds.setAdapter(mUserIdsAdapter);
@@ -218,7 +229,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
/**
* handles the UI bits of the signing process on the UI thread
*/
- private void initiateSigning() {
+ private void initiateCertifying() {
// get the user's passphrase for this key (if required)
String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId);
if (passphrase == null) {
@@ -227,27 +238,27 @@ public class CertifyKeyActivity extends ActionBarActivity implements
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
- startSigning();
+ startCertifying();
}
}
- });
+ }
+ );
// bail out; need to wait until the user has entered the passphrase before trying again
return;
} else {
- startSigning();
+ startCertifying();
}
}
/**
* kicks off the actual signing process on a background thread
*/
- private void startSigning() {
-
+ private void startCertifying() {
// Bail out if there is not at least one user id selected
ArrayList<String> userIds = mUserIdsAdapter.getSelectedUserIds();
if (userIds.isEmpty()) {
- AppMsg.makeText(CertifyKeyActivity.this, "No User IDs to sign selected!",
- AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(CertifyKeyActivity.this, "No identities selected!",
+ Notify.Style.ERROR);
return;
}
@@ -267,15 +278,15 @@ public class CertifyKeyActivity extends ActionBarActivity implements
// Message is received after signing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- getString(R.string.progress_signing), ProgressDialog.STYLE_SPINNER) {
+ getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- AppMsg.makeText(CertifyKeyActivity.this, R.string.key_certify_success,
- AppMsg.STYLE_INFO).show();
+ Notify.showNotify(CertifyKeyActivity.this, R.string.key_certify_success,
+ Notify.Style.INFO);
// check if we need to send the key to the server or not
if (mUploadKeyCheckbox.isChecked()) {
@@ -321,14 +332,16 @@ public class CertifyKeyActivity extends ActionBarActivity implements
// Message is received after uploading is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) {
+ getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- AppMsg.makeText(CertifyKeyActivity.this, R.string.key_send_success,
- AppMsg.STYLE_INFO).show();
+ Intent intent = new Intent();
+ intent.putExtra(OperationResultParcel.EXTRA_RESULT, message.getData());
+ Notify.showNotify(CertifyKeyActivity.this, R.string.key_send_success,
+ Notify.Style.INFO);
setResult(RESULT_OK);
finish();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
index d2073d9a7..534ac5811 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
@@ -17,171 +17,69 @@
package org.sufficientlysecure.keychain.ui;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBarActivity;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Patterns;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.Button;
-import android.widget.EditText;
-import org.spongycastle.bcpg.sig.KeyFlags;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ContactHelper;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
-
-import java.util.regex.Matcher;
public class CreateKeyActivity extends ActionBarActivity {
- AutoCompleteTextView nameEdit;
- AutoCompleteTextView emailEdit;
- EditText passphraseEdit;
- Button createButton;
+ public static final String EXTRA_NAME = "name";
+ public static final String EXTRA_EMAIL = "email";
+
+ public static final int FRAG_ACTION_START = 0;
+ public static final int FRAG_ACTION_TO_RIGHT = 1;
+ public static final int FRAG_ACTION_TO_LEFT = 2;
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.create_key_activity);
- nameEdit = (AutoCompleteTextView) findViewById(R.id.name);
- emailEdit = (AutoCompleteTextView) findViewById(R.id.email);
- passphraseEdit = (EditText) findViewById(R.id.passphrase);
- createButton = (Button) findViewById(R.id.create_key_button);
-
- emailEdit.setThreshold(1); // Start working from first character
- emailEdit.setAdapter(
- new ArrayAdapter<String>
- (this, android.R.layout.simple_spinner_dropdown_item,
- ContactHelper.getPossibleUserEmails(this)
- )
- );
- emailEdit.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()) {
- emailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_ok, 0);
- } else {
- emailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_bad, 0);
- }
- } else {
- // remove drawable if email is empty
- emailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
- }
- });
- nameEdit.setThreshold(1); // Start working from first character
- nameEdit.setAdapter(
- new ArrayAdapter<String>
- (this, android.R.layout.simple_spinner_dropdown_item,
- ContactHelper.getPossibleUserNames(this)
- )
- );
-
- createButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- createKeyCheck();
- }
- });
-
+ // pass extras into fragment
+ CreateKeyInputFragment frag =
+ CreateKeyInputFragment.newInstance(
+ getIntent().getStringExtra(EXTRA_NAME),
+ getIntent().getStringExtra(EXTRA_EMAIL)
+ );
+ loadFragment(null, frag, FRAG_ACTION_START);
}
- private void createKeyCheck() {
- if (isEditTextNotEmpty(this, nameEdit)
- && isEditTextNotEmpty(this, emailEdit)
- && isEditTextNotEmpty(this, passphraseEdit)) {
- createKey();
+ public void loadFragment(Bundle savedInstanceState, Fragment fragment, int action) {
+ // 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;
}
- }
-
- private void createKey() {
- Intent intent = new Intent(this, KeychainIntentService.class);
- intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
-
- // 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) {
- CreateKeyActivity.this.finish();
- }
- }
- };
+ // Add the fragment to the 'fragment_container' FrameLayout
+ // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+
+ switch (action) {
+ case FRAG_ACTION_START:
+ transaction.setCustomAnimations(0, 0);
+ transaction.replace(R.id.create_key_fragment_container, fragment)
+ .commitAllowingStateLoss();
+ break;
+ case FRAG_ACTION_TO_LEFT:
+ getSupportFragmentManager().popBackStackImmediate();
+ break;
+ case FRAG_ACTION_TO_RIGHT:
+ transaction.setCustomAnimations(R.anim.frag_slide_in_from_right, R.anim.frag_slide_out_to_left,
+ R.anim.frag_slide_in_from_left, R.anim.frag_slide_out_to_right);
+ transaction.addToBackStack(null);
+ transaction.replace(R.id.create_key_fragment_container, fragment)
+ .commitAllowingStateLoss();
+ break;
- // fill values for this action
- Bundle data = new Bundle();
-
- SaveKeyringParcel parcel = new SaveKeyringParcel();
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.CERTIFY_OTHER, null));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.SIGN_DATA, null));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, null));
- String userId = nameEdit.getText().toString() + " <" + emailEdit.getText().toString() + ">";
- parcel.mAddUserIds.add(userId);
- parcel.mNewPassphrase = passphraseEdit.getText().toString();
-
- // get selected key entries
- data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, parcel);
-
- intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- saveHandler.showProgressDialog(this);
-
- startService(intent);
- }
-
- /**
- * Checks if text of given EditText is not empty. If it is empty an error is
- * set and the EditText gets the focus.
- *
- * @param context
- * @param editText
- * @return true if EditText is not empty
- */
- private static boolean isEditTextNotEmpty(Context context, EditText editText) {
- boolean output = true;
- if (editText.getText().toString().length() == 0) {
- editText.setError("empty!");
- editText.requestFocus();
- output = false;
- } else {
- editText.setError(null);
}
-
- return output;
+ // do it immediately!
+ getSupportFragmentManager().executePendingTransactions();
}
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
new file mode 100644
index 000000000..f9ed16cba
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -0,0 +1,249 @@
+/*
+ * 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;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import org.spongycastle.bcpg.sig.KeyFlags;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
+import org.sufficientlysecure.keychain.service.OperationResults;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.util.Notify;
+
+public class CreateKeyFinalFragment extends Fragment {
+
+ CreateKeyActivity mCreateKeyActivity;
+
+ TextView mNameEdit;
+ TextView mEmailEdit;
+ CheckBox mUploadCheckbox;
+ View mBackButton;
+ View mCreateButton;
+
+ public static final String ARG_NAME = "name";
+ public static final String ARG_EMAIL = "email";
+ public static final String ARG_PASSPHRASE = "passphrase";
+
+ String mName;
+ String mEmail;
+ String mPassphrase;
+
+ /**
+ * Creates new instance of this fragment
+ */
+ public static CreateKeyFinalFragment newInstance(String name, String email, String passphrase) {
+ CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
+
+ Bundle args = new Bundle();
+ args.putString(ARG_NAME, name);
+ args.putString(ARG_EMAIL, email);
+ args.putString(ARG_PASSPHRASE, passphrase);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.create_key_final_fragment, container, false);
+
+ mNameEdit = (TextView) view.findViewById(R.id.name);
+ mEmailEdit = (TextView) view.findViewById(R.id.email);
+ mUploadCheckbox = (CheckBox) view.findViewById(R.id.create_key_upload);
+ mBackButton = view.findViewById(R.id.create_key_back_button);
+ mCreateButton = view.findViewById(R.id.create_key_create_button);
+
+ // get args
+ mName = getArguments().getString(ARG_NAME);
+ mEmail = getArguments().getString(ARG_EMAIL);
+ mPassphrase = getArguments().getString(ARG_PASSPHRASE);
+
+ // set values
+ mNameEdit.setText(mName);
+ mEmailEdit.setText(mEmail);
+
+ mCreateButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ createKey();
+ }
+ });
+
+ mBackButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mCreateKeyActivity.loadFragment(null, null, CreateKeyActivity.FRAG_ACTION_TO_LEFT);
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ mCreateKeyActivity = (CreateKeyActivity) getActivity();
+ }
+
+ private void createKey() {
+ Intent intent = new Intent(getActivity(), KeychainIntentService.class);
+ intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
+
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ getActivity(),
+ 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();
+ if (returnData == null) {
+ return;
+ }
+ final OperationResults.EditKeyResult result =
+ returnData.getParcelable(OperationResultParcel.EXTRA_RESULT);
+ if (result == null) {
+ return;
+ }
+
+ if (result.getResult() == OperationResultParcel.RESULT_OK) {
+ if (mUploadCheckbox.isChecked()) {
+ // result will be displayed after upload
+ uploadKey(result);
+ } else {
+ // TODO: return result
+ result.createNotify(getActivity());
+
+ getActivity().setResult(Activity.RESULT_OK);
+ getActivity().finish();
+ }
+ } else {
+ // display result on error without finishing activity
+ result.createNotify(getActivity());
+ }
+ }
+ }
+ };
+
+ // fill values for this action
+ Bundle data = new Bundle();
+
+ SaveKeyringParcel parcel = new SaveKeyringParcel();
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.CERTIFY_OTHER, null));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.SIGN_DATA, null));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, null));
+ String userId = mName + " <" + mEmail + ">";
+ parcel.mAddUserIds.add(userId);
+ parcel.mNewPassphrase = mPassphrase;
+
+ // get selected key entries
+ data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, parcel);
+
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ saveHandler.showProgressDialog(getActivity());
+
+ getActivity().startService(intent);
+ }
+
+ private void uploadKey(final OperationResults.EditKeyResult editKeyResult) {
+ // Send all information needed to service to upload key in other thread
+ final Intent intent = new Intent(getActivity(), KeychainIntentService.class);
+
+ intent.setAction(KeychainIntentService.ACTION_UPLOAD_KEYRING);
+
+ // set data uri as path to keyring
+ Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(
+ editKeyResult.mRingMasterKeyId);
+ intent.setData(blobUri);
+
+ // fill values for this action
+ Bundle data = new Bundle();
+
+ // upload to favorite keyserver
+ String keyserver = Preferences.getPreferences(getActivity()).getKeyServers()[0];
+ data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, keyserver);
+
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Message is received after uploading is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
+ getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ // TODO: not supported by upload?
+// if (result.getResult() == OperationResultParcel.RESULT_OK) {
+ // TODO: return result
+ editKeyResult.createNotify(getActivity());
+
+ Notify.showNotify(getActivity(), R.string.key_send_success,
+ Notify.Style.INFO);
+
+ getActivity().setResult(Activity.RESULT_OK);
+ getActivity().finish();
+// } else {
+// // display result on error without finishing activity
+// editKeyResult.createNotify(getActivity());
+// }
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ // show progress dialog
+ saveHandler.showProgressDialog(getActivity());
+
+ // start service with intent
+ getActivity().startService(intent);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java
new file mode 100644
index 000000000..ef5a3b145
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java
@@ -0,0 +1,214 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Patterns;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.EditText;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
+
+import java.util.regex.Matcher;
+
+public class CreateKeyInputFragment extends Fragment {
+
+ CreateKeyActivity mCreateKeyActivity;
+
+ AutoCompleteTextView mNameEdit;
+ AutoCompleteTextView mEmailEdit;
+ EditText mPassphraseEdit;
+ EditText mPassphraseEditAgain;
+ View mCreateButton;
+
+ public static final String ARG_NAME = "name";
+ public static final String ARG_EMAIL = "email";
+
+ /**
+ * Creates new instance of this fragment
+ */
+ public static CreateKeyInputFragment newInstance(String name, String email) {
+ CreateKeyInputFragment frag = new CreateKeyInputFragment();
+
+ Bundle args = new Bundle();
+ args.putString(ARG_NAME, name);
+ args.putString(ARG_EMAIL, email);
+
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.create_key_input_fragment, container, false);
+
+ mNameEdit = (AutoCompleteTextView) view.findViewById(R.id.name);
+ mEmailEdit = (AutoCompleteTextView) view.findViewById(R.id.email);
+ mPassphraseEdit = (EditText) view.findViewById(R.id.passphrase);
+ mPassphraseEditAgain = (EditText) view.findViewById(R.id.passphrase_again);
+ mCreateButton = view.findViewById(R.id.create_key_button);
+
+ // initial values
+ String name = getArguments().getString(ARG_NAME);
+ String email = getArguments().getString(ARG_EMAIL);
+ mNameEdit.setText(name);
+ mEmailEdit.setText(email);
+
+ // focus non-empty edit fields
+ if (name != null && email != null) {
+ mPassphraseEdit.requestFocus();
+ } else if (name != null) {
+ mEmailEdit.requestFocus();
+ }
+
+ mEmailEdit.setThreshold(1); // Start working from first character
+ mEmailEdit.setAdapter(
+ new ArrayAdapter<String>
+ (getActivity(), android.R.layout.simple_spinner_dropdown_item,
+ ContactHelper.getPossibleUserEmails(getActivity())
+ )
+ );
+ mEmailEdit.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()) {
+ mEmailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_ok, 0);
+ } else {
+ mEmailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_bad, 0);
+ }
+ } else {
+ // remove drawable if email is empty
+ mEmailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+ }
+ }
+ });
+
+ mNameEdit.setThreshold(1); // Start working from first character
+ mNameEdit.setAdapter(
+ new ArrayAdapter<String>
+ (getActivity(), android.R.layout.simple_spinner_dropdown_item,
+ ContactHelper.getPossibleUserNames(getActivity())
+ )
+ );
+
+ mCreateButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ createKeyCheck();
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ mCreateKeyActivity = (CreateKeyActivity) getActivity();
+ }
+
+ private void createKeyCheck() {
+ if (isEditTextNotEmpty(getActivity(), mNameEdit)
+ && isEditTextNotEmpty(getActivity(), mEmailEdit)
+ && isEditTextNotEmpty(getActivity(), mPassphraseEdit)
+ && areEditTextsEqual(getActivity(), mPassphraseEdit, mPassphraseEditAgain)) {
+
+ CreateKeyFinalFragment frag =
+ CreateKeyFinalFragment.newInstance(
+ mNameEdit.getText().toString(),
+ mEmailEdit.getText().toString(),
+ mPassphraseEdit.getText().toString()
+ );
+
+ hideKeyboard();
+ mCreateKeyActivity.loadFragment(null, frag, CreateKeyActivity.FRAG_ACTION_TO_RIGHT);
+ }
+ }
+
+ private void hideKeyboard() {
+ InputMethodManager inputManager = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ //check if no view has focus:
+ View v = getActivity().getCurrentFocus();
+ if (v == null)
+ return;
+
+ inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ }
+
+ /**
+ * Checks if text of given EditText is not empty. If it is empty an error is
+ * set and the EditText gets the focus.
+ *
+ * @param context
+ * @param editText
+ * @return true if EditText is not empty
+ */
+ private static boolean isEditTextNotEmpty(Context context, EditText editText) {
+ boolean output = true;
+ if (editText.getText().toString().length() == 0) {
+ editText.setError(context.getString(R.string.create_key_empty));
+ editText.requestFocus();
+ output = false;
+ } else {
+ editText.setError(null);
+ }
+
+ return output;
+ }
+
+ private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
+ boolean output = true;
+ if (!editText1.getText().toString().equals(editText2.getText().toString())) {
+ editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
+ editText2.requestFocus();
+ output = false;
+ } else {
+ editText2.setError(null);
+ }
+
+ return output;
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java
index c12b5b7be..56dfdbd95 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java
@@ -34,8 +34,6 @@ import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
@@ -129,7 +127,6 @@ public class DecryptFileFragment extends DecryptFragment {
}
if (mInputFilename.equals("")) {
- //AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
Notify.showNotify(getActivity(), R.string.no_file_selected, Notify.Style.ERROR);
return;
}
@@ -137,11 +134,8 @@ public class DecryptFileFragment extends DecryptFragment {
if (mInputUri == null && mInputFilename.startsWith("file")) {
File file = new File(mInputFilename);
if (!file.exists() || !file.isFile()) {
- AppMsg.makeText(
- getActivity(),
- getString(R.string.error_message,
- getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT)
- .show();
+ Notify.showNotify(getActivity(), getString(R.string.error_message,
+ getString(R.string.error_file_not_found)), Notify.Style.ERROR);
return;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
index 6b8358538..d4235b82b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java
@@ -132,7 +132,7 @@ public class DecryptFragment extends Fragment {
mResultText.setText(R.string.decrypt_result_decrypted_and_signature_certified);
}
- mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_green));
+ mResultLayout.setBackgroundColor(getResources().getColor(R.color.android_green_light));
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
mSignatureLayout.setVisibility(View.VISIBLE);
mLookupKey.setVisibility(View.GONE);
@@ -146,7 +146,7 @@ public class DecryptFragment extends Fragment {
mResultText.setText(R.string.decrypt_result_decrypted_and_signature_uncertified);
}
- mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_orange));
+ mResultLayout.setBackgroundColor(getResources().getColor(R.color.android_orange_light));
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
mSignatureLayout.setVisibility(View.VISIBLE);
mLookupKey.setVisibility(View.GONE);
@@ -160,7 +160,7 @@ public class DecryptFragment extends Fragment {
mResultText.setText(R.string.decrypt_result_decrypted_unknown_pub_key);
}
- mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_orange));
+ mResultLayout.setBackgroundColor(getResources().getColor(R.color.android_orange_light));
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mSignatureLayout.setVisibility(View.VISIBLE);
mLookupKey.setVisibility(View.VISIBLE);
@@ -170,7 +170,7 @@ public class DecryptFragment extends Fragment {
case OpenPgpSignatureResult.SIGNATURE_ERROR: {
mResultText.setText(R.string.decrypt_result_invalid_signature);
- mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_red));
+ mResultLayout.setBackgroundColor(getResources().getColor(R.color.android_red_light));
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mSignatureLayout.setVisibility(View.GONE);
mLookupKey.setVisibility(View.GONE);
@@ -180,7 +180,7 @@ public class DecryptFragment extends Fragment {
default: {
mResultText.setText(R.string.error);
- mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_red));
+ mResultLayout.setBackgroundColor(getResources().getColor(R.color.android_red_light));
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mSignatureLayout.setVisibility(View.GONE);
mLookupKey.setVisibility(View.GONE);
@@ -192,7 +192,7 @@ public class DecryptFragment extends Fragment {
mLookupKey.setVisibility(View.GONE);
// successful decryption-only
- mResultLayout.setBackgroundColor(getResources().getColor(R.color.result_purple));
+ mResultLayout.setBackgroundColor(getResources().getColor(R.color.android_purple_light));
mResultText.setText(R.string.decrypt_result_decrypted);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java
index 46462f924..cf7a0b4b8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java
@@ -28,8 +28,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
@@ -38,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.util.regex.Matcher;
@@ -107,12 +106,10 @@ public class DecryptMessageFragment extends DecryptFragment {
mCiphertext = matcher.group(1);
decryptStart(null);
} else {
- AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_ALERT)
- .show();
+ Notify.showNotify(getActivity(), R.string.error_invalid_data, Notify.Style.ERROR);
}
} else {
- AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_ALERT)
- .show();
+ Notify.showNotify(getActivity(), R.string.error_invalid_data, Notify.Style.ERROR);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
index d80425c3c..6ddaec17f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
@@ -33,7 +33,7 @@ public class EditKeyActivity extends ActionBarActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.edit_key_activity_new);
+ setContentView(R.layout.edit_key_activity);
Uri dataUri = getIntent().getData();
if (dataUri == null) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java
deleted file mode 100644
index 70ccb8800..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java
+++ /dev/null
@@ -1,744 +0,0 @@
-/*
- * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui;
-
-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.v4.app.ActivityCompat;
-import android.support.v7.app.ActionBarActivity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import com.devspark.appmsg.AppMsg;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ActionBarHelper;
-import org.sufficientlysecure.keychain.helper.ExportHelper;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
-import org.sufficientlysecure.keychain.pgp.UncachedSecretKey;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
-import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
-import org.sufficientlysecure.keychain.ui.widget.Editor;
-import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
-import org.sufficientlysecure.keychain.ui.widget.KeyEditor;
-import org.sufficientlysecure.keychain.ui.widget.SectionView;
-import org.sufficientlysecure.keychain.ui.widget.UserIdEditor;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Vector;
-
-public class EditKeyActivityOld extends ActionBarActivity implements EditorListener {
-
- // Actions for internal use only:
- public static final String ACTION_CREATE_KEY = Constants.INTENT_PREFIX + "CREATE_KEY";
- public static final String ACTION_EDIT_KEY = Constants.INTENT_PREFIX + "EDIT_KEY";
-
- // possible extra keys
- public static final String EXTRA_USER_IDS = "user_ids";
- public static final String EXTRA_NO_PASSPHRASE = "no_passphrase";
- public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generate_default_keys";
-
- // EDIT
- private Uri mDataUri;
-
- private SectionView mUserIdsView;
- private SectionView mKeysView;
-
- private String mCurrentPassphrase = null;
- private String mNewPassphrase = null;
- private String mSavedNewPassphrase = null;
- private boolean mIsPassphraseSet;
- private boolean mNeedsSaving;
- private boolean mIsBrandNewKeyring = false;
-
- private Button mChangePassphrase;
-
- private CheckBox mNoPassphrase;
-
- Vector<String> mUserIds;
- Vector<UncachedSecretKey> mKeys;
- Vector<Integer> mKeysUsages;
- boolean mMasterCanSign = true;
-
- ExportHelper mExportHelper;
-
- public boolean needsSaving() {
- mNeedsSaving = (mUserIdsView == null) ? false : mUserIdsView.needsSaving();
- mNeedsSaving |= (mKeysView == null) ? false : mKeysView.needsSaving();
- mNeedsSaving |= hasPassphraseChanged();
- mNeedsSaving |= mIsBrandNewKeyring;
- return mNeedsSaving;
- }
-
-
- public void somethingChanged() {
- ActivityCompat.invalidateOptionsMenu(this);
- }
-
- public void onDeleted(Editor e, boolean wasNewItem) {
- somethingChanged();
- }
-
- public void onEdited() {
- somethingChanged();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mExportHelper = new ExportHelper(this);
-
- // Inflate a "Done"/"Cancel" custom action bar view
- ActionBarHelper.setTwoButtonView(getSupportActionBar(),
- R.string.btn_save, R.drawable.ic_action_save,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Save
- saveClicked();
- }
- }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Cancel
- cancelClicked();
- }
- }
- );
-
- mUserIds = new Vector<String>();
- mKeys = new Vector<UncachedSecretKey>();
- mKeysUsages = new Vector<Integer>();
-
- // Catch Intents opened from other apps
- Intent intent = getIntent();
- String action = intent.getAction();
- if (ACTION_CREATE_KEY.equals(action)) {
- handleActionCreateKey(intent);
- } else if (ACTION_EDIT_KEY.equals(action)) {
- handleActionEditKey(intent);
- }
- }
-
- /**
- * Handle intent action to create new key
- *
- * @param intent
- */
- private void handleActionCreateKey(Intent intent) {
- Bundle extras = intent.getExtras();
-
- mCurrentPassphrase = "";
- mIsBrandNewKeyring = true;
-
- if (extras != null) {
- // if userId is given, prefill the fields
- if (extras.containsKey(EXTRA_USER_IDS)) {
- Log.d(Constants.TAG, "UserIds are given!");
- mUserIds.add(extras.getString(EXTRA_USER_IDS));
- }
-
- // if no passphrase is given
- if (extras.containsKey(EXTRA_NO_PASSPHRASE)) {
- boolean noPassphrase = extras.getBoolean(EXTRA_NO_PASSPHRASE);
- if (noPassphrase) {
- // check "no passphrase" checkbox and remove button
- mNoPassphrase.setChecked(true);
- mChangePassphrase.setVisibility(View.GONE);
- }
- }
-
- // generate key
- if (extras.containsKey(EXTRA_GENERATE_DEFAULT_KEYS)) {
- /*
- boolean generateDefaultKeys = extras.getBoolean(EXTRA_GENERATE_DEFAULT_KEYS);
- if (generateDefaultKeys) {
-
- // fill values for this action
- Bundle data = new Bundle();
- data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE,
- mCurrentPassphrase);
-
- serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data);
-
- // Message is received after generating is done in KeychainIntentService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
- this, getResources().getQuantityString(R.plurals.progress_generating, 1),
- ProgressDialog.STYLE_HORIZONTAL, true,
-
- new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- // Stop key generation on cancel
- stopService(serviceIntent);
- EditKeyActivity.this.setResult(Activity.RESULT_CANCELED);
- EditKeyActivity.this.finish();
- }
- }) {
-
- @Override
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- // get new key from data bundle returned from service
- Bundle data = message.getDataAsStringList();
-
- ArrayList<UncachedSecretKey> newKeys =
- PgpConversionHelper.BytesToPGPSecretKeyList(data
- .getByteArray(KeychainIntentService.RESULT_NEW_KEY));
-
- ArrayList<Integer> keyUsageFlags = data.getIntegerArrayList(
- KeychainIntentService.RESULT_KEY_USAGES);
-
- if (newKeys.size() == keyUsageFlags.size()) {
- for (int i = 0; i < newKeys.size(); ++i) {
- mKeys.add(newKeys.get(i));
- mKeysUsages.add(keyUsageFlags.get(i));
- }
- }
-
- buildLayout(true);
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- serviceIntent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- saveHandler.showProgressDialog(this);
-
- // start service with intent
- startService(serviceIntent);
- }
- */
- }
- } else {
- buildLayout(false);
- }
- }
-
- /**
- * Handle intent action to edit existing key
- *
- * @param intent
- */
- private void handleActionEditKey(Intent intent) {
- mDataUri = intent.getData();
- if (mDataUri == null) {
- Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!");
- finish();
- } else {
- Log.d(Constants.TAG, "uri: " + mDataUri);
-
- try {
- Uri secretUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
- WrappedSecretKeyRing keyRing = new ProviderHelper(this).getWrappedSecretKeyRing(secretUri);
-
- mMasterCanSign = keyRing.getSecretKey().canCertify();
- for (WrappedSecretKey key : keyRing.secretKeyIterator()) {
- // Turn into uncached instance
- mKeys.add(key.getUncached());
- mKeysUsages.add(key.getKeyUsage()); // get usage when view is created
- }
-
- boolean isSet = false;
- for (String userId : keyRing.getSecretKey().getUserIds()) {
- Log.d(Constants.TAG, "Added userId " + userId);
- if (!isSet) {
- isSet = true;
- String[] parts = KeyRing.splitUserId(userId);
- if (parts[0] != null) {
- setTitle(parts[0]);
- }
- }
- mUserIds.add(userId);
- }
-
- buildLayout(false);
-
- mCurrentPassphrase = "";
- mIsPassphraseSet = keyRing.hasPassphrase();
- if (!mIsPassphraseSet) {
- // check "no passphrase" checkbox and remove button
- mNoPassphrase.setChecked(true);
- mChangePassphrase.setVisibility(View.GONE);
- }
-
- } catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "Keyring not found: " + e.getMessage(), e);
- Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_SHORT).show();
- finish();
- }
-
- }
- }
-
- /**
- * Shows the dialog to set a new passphrase
- */
- private void showSetPassphraseDialog() {
- // Message is received after passphrase is cached
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
- Bundle data = message.getData();
-
- // set new returned passphrase!
- mNewPassphrase = data
- .getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE);
-
- updatePassphraseButtonText();
- somethingChanged();
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- // set title based on isPassphraseSet()
- int title;
- if (isPassphraseSet()) {
- title = R.string.title_change_passphrase;
- } else {
- title = R.string.title_set_passphrase;
- }
-
- SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
- messenger, null, title);
-
- setPassphraseDialog.show(getSupportFragmentManager(), "setPassphraseDialog");
- }
-
- /**
- * Build layout based on mUserId, mKeys and mKeysUsages Vectors. It creates Views for every user
- * id and key.
- *
- * @param newKeys
- */
- private void buildLayout(boolean newKeys) {
- setContentView(R.layout.edit_key_activity);
-
- // find views
- mChangePassphrase = (Button) 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(SectionView.TYPE_USER_ID);
- mUserIdsView.setCanBeEdited(mMasterCanSign);
- mUserIdsView.setUserIds(mUserIds);
- mUserIdsView.setEditorListener(this);
- container.addView(mUserIdsView);
- mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
- mKeysView.setType(SectionView.TYPE_KEY);
- mKeysView.setCanBeEdited(mMasterCanSign);
- mKeysView.setKeys(mKeys, mKeysUsages, newKeys);
- mKeysView.setEditorListener(this);
- container.addView(mKeysView);
-
- updatePassphraseButtonText();
-
- mChangePassphrase.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- showSetPassphraseDialog();
- }
- });
-
- // disable passphrase when no passphrase checkbox is checked!
- mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (isChecked) {
- // remove passphrase
- mSavedNewPassphrase = mNewPassphrase;
- mNewPassphrase = "";
- mChangePassphrase.setVisibility(View.GONE);
- } else {
- mNewPassphrase = mSavedNewPassphrase;
- mChangePassphrase.setVisibility(View.VISIBLE);
- }
- somethingChanged();
- }
- });
- }
-
- private long getMasterKeyId() {
- if (mKeysView.getEditors().getChildCount() == 0) {
- return 0;
- }
- return ((KeyEditor) mKeysView.getEditors().getChildAt(0)).getValue().getKeyId();
- }
-
- public boolean isPassphraseSet() {
- if (mNoPassphrase.isChecked()) {
- return true;
- } else if ((mIsPassphraseSet)
- || (mNewPassphrase != null && !mNewPassphrase.equals(""))) {
- return true;
- } else {
- return false;
- }
- }
-
- public boolean hasPassphraseChanged() {
- if (mNoPassphrase != null) {
- if (mNoPassphrase.isChecked()) {
- return mIsPassphraseSet;
- } else {
- return (mNewPassphrase != null && !mNewPassphrase.equals(""));
- }
- } else {
- return false;
- }
- }
-
- private void saveClicked() {
- final long masterKeyId = getMasterKeyId();
- if (needsSaving()) { //make sure, as some versions don't support invalidateOptionsMenu
- try {
- if (!isPassphraseSet()) {
- throw new PgpGeneralException(this.getString(R.string.set_a_passphrase));
- }
-
- String passphrase;
- if (mIsPassphraseSet) {
- passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
- } else {
- passphrase = "";
- }
- if (passphrase == null) {
- PassphraseDialogFragment.show(this, masterKeyId,
- new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
- mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(
- EditKeyActivityOld.this, masterKeyId);
- checkEmptyIDsWanted();
- }
- }
- });
- } else {
- mCurrentPassphrase = passphrase;
- checkEmptyIDsWanted();
- }
- } catch (PgpGeneralException e) {
- AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
- AppMsg.STYLE_ALERT).show();
- }
- } else {
- AppMsg.makeText(this, R.string.error_change_something_first, AppMsg.STYLE_ALERT).show();
- }
- }
-
- private void checkEmptyIDsWanted() {
- try {
- ArrayList<String> userIDs = getUserIds(mUserIdsView);
- List<Boolean> newIDs = mUserIdsView.getNewIDFlags();
- ArrayList<String> originalIDs = mUserIdsView.getOriginalIDs();
- int curID = 0;
- for (String userID : userIDs) {
- if (userID.equals("") && (!userID.equals(originalIDs.get(curID)) || newIDs.get(curID))) {
- CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(
- EditKeyActivityOld.this);
-
- alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
- alert.setTitle(R.string.warning);
- alert.setMessage(EditKeyActivityOld.this.getString(R.string.ask_empty_id_ok));
-
- alert.setPositiveButton(EditKeyActivityOld.this.getString(android.R.string.yes),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- finallySaveClicked();
- }
- }
- );
- alert.setNegativeButton(this.getString(android.R.string.no),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- }
- }
- );
- alert.setCancelable(false);
- alert.show();
- return;
- }
- curID++;
- }
- } catch (PgpGeneralException e) {
- Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
- AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()), AppMsg.STYLE_ALERT).show();
- }
- finallySaveClicked();
- }
-
- private boolean[] toPrimitiveArray(final List<Boolean> booleanList) {
- final boolean[] primitives = new boolean[booleanList.size()];
- int index = 0;
- for (Boolean object : booleanList) {
- primitives[index++] = object;
- }
- return primitives;
- }
-
- private void finallySaveClicked() {
- /*
- try {
- // Send all information needed to service to edit key in other thread
- Intent intent = new Intent(this, KeychainIntentService.class);
-
- intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
-
- OldSaveKeyringParcel saveParams = new OldSaveKeyringParcel();
- saveParams.userIds = getUserIds(mUserIdsView);
- saveParams.originalIDs = mUserIdsView.getOriginalIDs();
- saveParams.deletedIDs = mUserIdsView.getDeletedIDs();
- saveParams.newIDs = toPrimitiveArray(mUserIdsView.getNewIDFlags());
- saveParams.primaryIDChanged = mUserIdsView.primaryChanged();
- saveParams.moddedKeys = toPrimitiveArray(mKeysView.getNeedsSavingArray());
- saveParams.deletedKeys = mKeysView.getDeletedKeys();
- saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
- saveParams.keysUsages = getKeysUsages(mKeysView);
- saveParams.mNewPassphrase = mNewPassphrase;
- saveParams.oldPassphrase = mCurrentPassphrase;
- saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
- saveParams.keys = getKeys(mKeysView);
- saveParams.originalPrimaryID = mUserIdsView.getOriginalPrimaryID();
-
- // fill values for this action
- Bundle data = new Bundle();
- 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 KeychainIntentService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- getString(R.string.progress_saving), ProgressDialog.STYLE_HORIZONTAL) {
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- Intent data = new Intent();
-
- // return uri pointing to new created key
- Uri uri = KeyRings.buildGenericKeyRingUri(getMasterKeyId());
- data.setData(uri);
-
- setResult(RESULT_OK, data);
- finish();
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- saveHandler.showProgressDialog(this);
-
- // start service with intent
- startService(intent);
- } catch (PgpGeneralException e) {
- Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
- AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
- AppMsg.STYLE_ALERT).show();
- }
- */
- }
-
- private void cancelClicked() {
- if (needsSaving()) { //ask if we want to save
- CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(
- EditKeyActivityOld.this);
-
- alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
- alert.setTitle(R.string.warning);
- alert.setMessage(EditKeyActivityOld.this.getString(R.string.ask_save_changed_key));
-
- alert.setPositiveButton(EditKeyActivityOld.this.getString(android.R.string.yes),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- saveClicked();
- }
- });
- alert.setNegativeButton(this.getString(android.R.string.no),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- setResult(RESULT_CANCELED);
- finish();
- }
- });
- alert.setCancelable(false);
- alert.show();
- } else {
- setResult(RESULT_CANCELED);
- finish();
- }
- }
-
- /**
- * Returns user ids from the SectionView
- *
- * @param userIdsView
- * @return
- */
- private ArrayList<String> getUserIds(SectionView userIdsView) throws PgpGeneralException {
- ArrayList<String> userIds = new ArrayList<String>();
-
- ViewGroup userIdEditors = userIdsView.getEditors();
-
- boolean gotMainUserId = false;
- for (int i = 0; i < userIdEditors.getChildCount(); ++i) {
- UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i);
- String userId;
- userId = editor.getValue();
-
- if (editor.isMainUserId()) {
- userIds.add(0, userId);
- gotMainUserId = true;
- } else {
- userIds.add(userId);
- }
- }
-
- if (userIds.size() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_a_user_id));
- }
-
- if (!gotMainUserId) {
- throw new PgpGeneralException(getString(R.string.error_main_user_id_must_not_be_empty));
- }
-
- return userIds;
- }
-
- /**
- * Returns keys from the SectionView
- *
- * @param keysView
- * @return
- */
- private ArrayList<UncachedSecretKey> getKeys(SectionView keysView) throws PgpGeneralException {
- ArrayList<UncachedSecretKey> keys = new ArrayList<UncachedSecretKey>();
-
- ViewGroup keyEditors = keysView.getEditors();
-
- if (keyEditors.getChildCount() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
- }
-
- for (int i = 0; i < keyEditors.getChildCount(); ++i) {
- KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
- keys.add(editor.getValue());
- }
-
- return keys;
- }
-
- /**
- * Returns usage selections of keys from the SectionView
- *
- * @param keysView
- * @return
- */
- private ArrayList<Integer> getKeysUsages(SectionView keysView) throws PgpGeneralException {
- ArrayList<Integer> keysUsages = new ArrayList<Integer>();
-
- ViewGroup keyEditors = keysView.getEditors();
-
- if (keyEditors.getChildCount() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
- }
-
- for (int i = 0; i < keyEditors.getChildCount(); ++i) {
- KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
- keysUsages.add(editor.getUsage());
- }
-
- return keysUsages;
- }
-
- private ArrayList<Calendar> getKeysExpiryDates(SectionView keysView) throws PgpGeneralException {
- ArrayList<Calendar> keysExpiryDates = new ArrayList<Calendar>();
-
- ViewGroup keyEditors = keysView.getEditors();
-
- if (keyEditors.getChildCount() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
- }
-
- for (int i = 0; i < keyEditors.getChildCount(); ++i) {
- KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
- keysExpiryDates.add(editor.getExpiryDate());
- }
-
- return keysExpiryDates;
- }
-
- private void updatePassphraseButtonText() {
- mChangePassphrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase)
- : getString(R.string.btn_set_passphrase));
- }
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index b41871a39..9083d1567 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -42,12 +42,13 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
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.OperationResults;
+import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
@@ -167,8 +168,8 @@ public class EditKeyFragment extends LoaderFragment implements
try {
Uri secretUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri);
- WrappedSecretKeyRing keyRing =
- new ProviderHelper(getActivity()).getWrappedSecretKeyRing(secretUri);
+ CanonicalizedSecretKeyRing keyRing =
+ new ProviderHelper(getActivity()).getCanonicalizedSecretKeyRing(secretUri);
mSaveKeyringParcel = new SaveKeyringParcel(keyRing.getMasterKeyId(),
keyRing.getUncachedKeyRing().getFingerprint());
@@ -466,26 +467,30 @@ public class EditKeyFragment extends LoaderFragment implements
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- getActivity().finish();
- // TODO below
// get returned data bundle
Bundle returnData = message.getData();
if (returnData == null) {
return;
}
- final OperationResults.SaveKeyringResult result =
- returnData.getParcelable(KeychainIntentService.RESULT);
+ final OperationResults.EditKeyResult result =
+ returnData.getParcelable(EditKeyResult.EXTRA_RESULT);
if (result == null) {
return;
}
- // if good -> finish, return result to showkey and display there!
// if bad -> display here!
+ if (!result.success()) {
+ result.createNotify(getActivity()).show();
+ return;
+ }
-// result.displayNotify(ImportKeysActivity.this);
+ // if good -> finish, return result to showkey and display there!
+ Intent intent = new Intent();
+ intent.putExtra(EditKeyResult.EXTRA_RESULT, result);
+ getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
+ getActivity().finish();
-// getActivity().finish();
}
}
};
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index dc0510189..eb807792b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -31,11 +31,14 @@ import android.widget.Button;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.util.Vector;
@@ -195,22 +198,23 @@ public class EncryptAsymmetricFragment extends Fragment {
mMainUserIdRest.setText("");
} else {
// See if we can get a user_id from a unified query
- String[] userId;
try {
- userId = mProviderHelper.getCachedPublicKeyRing(
+ String[] userIdSplit = mProviderHelper.getCachedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(mSecretKeyId)).getSplitPrimaryUserIdWithFallback();
+
+ if (userIdSplit[0] != null) {
+ mMainUserId.setText(userIdSplit[0]);
+ } else {
+ mMainUserId.setText(R.string.user_id_no_name);
+ }
+ if (userIdSplit[1] != null) {
+ mMainUserIdRest.setText(userIdSplit[1]);
+ } else {
+ mMainUserIdRest.setText(getString(R.string.label_key_id) + ": "
+ + PgpKeyHelper.convertKeyIdToHex(mSecretKeyId));
+ }
} catch (PgpGeneralException e) {
- userId = null;
- }
- if (userId != null && userId[0] != null) {
- mMainUserId.setText(String.format("%#16x", Long.parseLong(userId[0])));
- } else {
- mMainUserId.setText(getResources().getString(R.string.user_id_no_name));
- }
- if (userId != null && userId[1] != null) {
- mMainUserIdRest.setText(userId[1]);
- } else {
- mMainUserIdRest.setText("");
+ Notify.showNotify(getActivity(), "Key not found! This is a bug!", Notify.Style.ERROR);
}
mSign.setChecked(true);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java
index f5d89d186..345e38a0e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java
@@ -37,8 +37,6 @@ import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Spinner;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
@@ -51,6 +49,7 @@ import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Choice;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.io.File;
@@ -58,7 +57,7 @@ public class EncryptFileFragment extends Fragment {
public static final String ARG_FILENAME = "filename";
public static final String ARG_ASCII_ARMOR = "ascii_armor";
- private static final int RESULT_CODE_FILE = 0x00007003;
+ private static final int REQUEST_CODE_FILE = 0x00007003;
private EncryptActivityInterface mEncryptInterface;
@@ -109,10 +108,10 @@ public class EncryptFileFragment extends Fragment {
mBrowse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (Constants.KITKAT) {
- FileHelper.openDocument(EncryptFileFragment.this, mInputUri, "*/*", RESULT_CODE_FILE);
+ FileHelper.openDocument(EncryptFileFragment.this, mInputUri, "*/*", REQUEST_CODE_FILE);
} else {
FileHelper.openFile(EncryptFileFragment.this, mFilename.getText().toString(), "*/*",
- RESULT_CODE_FILE);
+ REQUEST_CODE_FILE);
}
}
});
@@ -218,18 +217,18 @@ public class EncryptFileFragment extends Fragment {
}
if (mInputFilename.equals("")) {
- AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.no_file_selected, Notify.Style.ERROR);
return;
}
if (mInputUri == null && !mInputFilename.startsWith("content")) {
File file = new File(mInputFilename);
if (!file.exists() || !file.isFile()) {
- AppMsg.makeText(
+ Notify.showNotify(
getActivity(),
getString(R.string.error_message,
- getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT)
- .show();
+ getString(R.string.error_file_not_found)), Notify.Style.ERROR
+ );
return;
}
}
@@ -240,13 +239,13 @@ public class EncryptFileFragment extends Fragment {
boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
&& mEncryptInterface.getPassphrase().length() != 0);
if (!gotPassphrase) {
- AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
- .show();
+ Notify.showNotify(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR)
+ ;
return;
}
if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
- AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR);
return;
}
} else {
@@ -256,13 +255,13 @@ public class EncryptFileFragment extends Fragment {
&& mEncryptInterface.getEncryptionKeys().length > 0);
if (!gotEncryptionKeys) {
- AppMsg.makeText(getActivity(), R.string.select_encryption_key, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR);
return;
}
if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) {
- AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key,
- AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.select_encryption_or_signature_key,
+ Notify.Style.ERROR);
return;
}
@@ -345,8 +344,8 @@ public class EncryptFileFragment extends Fragment {
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- AppMsg.makeText(getActivity(), R.string.encrypt_sign_successful,
- AppMsg.STYLE_INFO).show();
+ Notify.showNotify(getActivity(), R.string.encrypt_sign_successful,
+ Notify.Style.INFO);
if (mDeleteAfter.isChecked()) {
// Create and show dialog to delete original file
@@ -390,7 +389,7 @@ public class EncryptFileFragment extends Fragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
- case RESULT_CODE_FILE: {
+ case REQUEST_CODE_FILE: {
if (resultCode == Activity.RESULT_OK && data != null) {
if (Constants.KITKAT) {
mInputUri = data.getData();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java
index 8a6103b16..e1760b4ed 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java
@@ -30,8 +30,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
@@ -41,6 +39,7 @@ 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 org.sufficientlysecure.keychain.util.Notify;
public class EncryptMessageFragment extends Fragment {
public static final String ARG_TEXT = "text";
@@ -126,13 +125,12 @@ public class EncryptMessageFragment extends Fragment {
boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null
&& mEncryptInterface.getPassphrase().length() != 0);
if (!gotPassphrase) {
- AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
- .show();
+ Notify.showNotify(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR);
return;
}
if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) {
- AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR);
return;
}
@@ -143,8 +141,8 @@ public class EncryptMessageFragment extends Fragment {
&& mEncryptInterface.getEncryptionKeys().length > 0);
if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) {
- AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key,
- AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.select_encryption_or_signature_key,
+ Notify.Style.ERROR);
return;
}
@@ -226,9 +224,8 @@ public class EncryptMessageFragment extends Fragment {
if (toClipboard) {
ClipboardReflection.copyToClipboard(getActivity(), output);
- AppMsg.makeText(getActivity(),
- R.string.encrypt_sign_clipboard_successful, AppMsg.STYLE_INFO)
- .show();
+ Notify.showNotify(getActivity(),
+ R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO);
} else {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
index aa4120d2c..5f3f170a1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
@@ -22,15 +22,19 @@ import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.Window;
-import android.widget.Button;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.util.Log;
public class FirstTimeActivity extends ActionBarActivity {
- Button mCreateKey;
- Button mImportKey;
- Button mSkipSetup;
+ View mCreateKey;
+ View mImportKey;
+ View mSkipSetup;
+
+ public static final int REQUEST_CODE_CREATE_OR_IMPORT_KEY = 0x00007012;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -40,16 +44,14 @@ public class FirstTimeActivity extends ActionBarActivity {
setContentView(R.layout.first_time_activity);
- mCreateKey = (Button) findViewById(R.id.first_time_create_key);
- mImportKey = (Button) findViewById(R.id.first_time_import_key);
- mSkipSetup = (Button) findViewById(R.id.first_time_cancel);
+ mCreateKey = findViewById(R.id.first_time_create_key);
+ mImportKey = findViewById(R.id.first_time_import_key);
+ mSkipSetup = findViewById(R.id.first_time_cancel);
mSkipSetup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- Intent intent = new Intent(FirstTimeActivity.this, KeyListActivity.class);
- startActivity(intent);
- finish();
+ finishSetup();
}
});
@@ -58,8 +60,7 @@ public class FirstTimeActivity extends ActionBarActivity {
public void onClick(View v) {
Intent intent = new Intent(FirstTimeActivity.this, ImportKeysActivity.class);
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN);
- startActivity(intent);
- finish();
+ startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
}
});
@@ -67,11 +68,30 @@ public class FirstTimeActivity extends ActionBarActivity {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstTimeActivity.this, CreateKeyActivity.class);
- startActivity(intent);
- finish();
+ startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
}
});
}
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == REQUEST_CODE_CREATE_OR_IMPORT_KEY) {
+ if (resultCode == RESULT_OK) {
+ finishSetup();
+ }
+ } else {
+ Log.e(Constants.TAG, "No valid request code!");
+ }
+ }
+
+ private void finishSetup() {
+ Preferences prefs = Preferences.getPreferences(this);
+ prefs.setFirstTime(false);
+ Intent intent = new Intent(FirstTimeActivity.this, KeyListActivity.class);
+ startActivity(intent);
+ finish();
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 3ff3b56bf..dbc557f9a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -40,17 +40,19 @@ 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.keyimport.FileImportCache;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.OperationResults.ImportResult;
+import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Notify;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;
@@ -98,6 +100,7 @@ public class ImportKeysActivity extends ActionBarActivity {
public static final int VIEW_PAGER_HEIGHT = 64; // dp
+ private static final int ALL_TABS = -1;
private static final int TAB_KEYSERVER = 0;
private static final int TAB_QR_CODE = 1;
private static final int TAB_FILE = 2;
@@ -150,7 +153,7 @@ public class ImportKeysActivity extends ActionBarActivity {
}
Bundle serverBundle = null;
- boolean serverOnly = false;
+ int showTabOnly = ALL_TABS;
if (ACTION_IMPORT_KEY.equals(action)) {
/* Keychain's own Actions */
@@ -214,7 +217,7 @@ public class ImportKeysActivity extends ActionBarActivity {
serverBundle.putString(ImportKeysServerFragment.ARG_QUERY, query);
serverBundle.putBoolean(ImportKeysServerFragment.ARG_DISABLE_QUERY_EDIT, true);
// display server tab only
- serverOnly = true;
+ showTabOnly = TAB_KEYSERVER;
mSwitchToTab = TAB_KEYSERVER;
// action: search immediately
@@ -227,13 +230,20 @@ public class ImportKeysActivity extends ActionBarActivity {
);
return;
}
- } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)
- || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(action)) {
+ } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) {
// NOTE: this only displays the appropriate fragment, no actions are taken
mSwitchToTab = TAB_FILE;
// no immediate actions!
startListFragment(savedInstanceState, null, null, null);
+ } else if (ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(action)) {
+ // NOTE: this only displays the appropriate fragment, no actions are taken
+ mSwitchToTab = TAB_FILE;
+ // display file tab only
+ showTabOnly = TAB_FILE;
+
+ // no immediate actions!
+ startListFragment(savedInstanceState, null, null, null);
} else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) {
// also exposed in AndroidManifest
@@ -259,10 +269,10 @@ public class ImportKeysActivity extends ActionBarActivity {
startListFragment(savedInstanceState, null, null, null);
}
- initTabs(serverBundle, serverOnly);
+ initTabs(serverBundle, showTabOnly);
}
- private void initTabs(Bundle serverBundle, boolean serverOnly) {
+ private void initTabs(Bundle serverBundle, int showTabOnly) {
mTabsAdapter = new PagerTabStripAdapter(this);
mViewPager.setAdapter(mTabsAdapter);
mSlidingTabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@@ -285,15 +295,34 @@ public class ImportKeysActivity extends ActionBarActivity {
}
});
- mTabsAdapter.addTab(ImportKeysServerFragment.class,
- serverBundle, getString(R.string.import_tab_keyserver));
- if (!serverOnly) {
- mTabsAdapter.addTab(ImportKeysQrCodeFragment.class,
- null, getString(R.string.import_tab_qr_code));
- mTabsAdapter.addTab(ImportKeysFileFragment.class,
- null, getString(R.string.import_tab_direct));
- mTabsAdapter.addTab(ImportKeysKeybaseFragment.class,
- null, getString(R.string.import_tab_keybase));
+ switch (showTabOnly) {
+ case ALL_TABS:
+ // show all tabs
+ mTabsAdapter.addTab(ImportKeysServerFragment.class,
+ serverBundle, getString(R.string.import_tab_keyserver));
+ mTabsAdapter.addTab(ImportKeysQrCodeFragment.class,
+ null, getString(R.string.import_tab_qr_code));
+ mTabsAdapter.addTab(ImportKeysFileFragment.class,
+ null, getString(R.string.import_tab_direct));
+ mTabsAdapter.addTab(ImportKeysKeybaseFragment.class,
+ null, getString(R.string.import_tab_keybase));
+ break;
+ case TAB_KEYSERVER:
+ mTabsAdapter.addTab(ImportKeysServerFragment.class,
+ serverBundle, getString(R.string.import_tab_keyserver));
+ break;
+ case TAB_QR_CODE:
+ mTabsAdapter.addTab(ImportKeysQrCodeFragment.class,
+ null, getString(R.string.import_tab_qr_code));
+ break;
+ case TAB_FILE:
+ mTabsAdapter.addTab(ImportKeysFileFragment.class,
+ null, getString(R.string.import_tab_direct));
+ break;
+ case TAB_KEYBASE:
+ mTabsAdapter.addTab(ImportKeysKeybaseFragment.class,
+ null, getString(R.string.import_tab_keybase));
+ break;
}
// update layout after operations
@@ -354,9 +383,8 @@ public class ImportKeysActivity extends ActionBarActivity {
ImportKeysServerFragment f = (ImportKeysServerFragment)
getActiveFragment(mViewPager, TAB_KEYSERVER);
- // TODO: Currently it simply uses keyserver nr 0
- String keyserver = Preferences.getPreferences(ImportKeysActivity.this)
- .getKeyServers()[0];
+ // ask favorite keyserver
+ String keyserver = Preferences.getPreferences(ImportKeysActivity.this).getKeyServers()[0];
// set fields of ImportKeysServerFragment
f.setQueryAndKeyserver(query, keyserver);
@@ -427,15 +455,15 @@ public class ImportKeysActivity extends ActionBarActivity {
if (returnData == null) {
return;
}
- final ImportResult result =
- returnData.getParcelable(KeychainIntentService.RESULT);
+ final ImportKeyResult result =
+ returnData.getParcelable(KeychainIntentService.RESULT_IMPORT);
if (result == null) {
return;
}
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())) {
Intent intent = new Intent();
- intent.putExtra(EXTRA_RESULT, result);
+ intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
ImportKeysActivity.this.setResult(RESULT_OK, intent);
ImportKeysActivity.this.finish();
return;
@@ -451,7 +479,7 @@ public class ImportKeysActivity extends ActionBarActivity {
return;
}
- result.displayNotify(ImportKeysActivity.this);
+ result.createNotify(ImportKeysActivity.this).show();
}
}
};
@@ -470,19 +498,29 @@ public class ImportKeysActivity extends ActionBarActivity {
// get DATA from selected key entries
ArrayList<ParcelableKeyRing> selectedEntries = mListFragment.getSelectedData();
- data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, selectedEntries);
- intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+ // instead of given the entries by Intent extra, cache them into a file
+ // to prevent Java Binder problems on heavy imports
+ // read FileImportCache for more info.
+ try {
+ FileImportCache cache = new FileImportCache(this);
+ cache.writeCache(selectedEntries);
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
- // show progress dialog
- saveHandler.showProgressDialog(this);
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
- // start service with intent
- startService(intent);
+ // show progress dialog
+ saveHandler.showProgressDialog(this);
+
+ // start service with intent
+ startService(intent);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Problem writing cache file", e);
+ Notify.showNotify(this, "Problem writing cache file!", Notify.Style.ERROR);
+ }
} else if (ls instanceof ImportKeysListFragment.KeyserverLoaderState) {
ImportKeysListFragment.KeyserverLoaderState sls = (ImportKeysListFragment.KeyserverLoaderState) ls;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
index 9a39b6cc3..fde0f5f23 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
@@ -35,7 +35,6 @@ import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.Keyserver;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListKeybaseLoader;
@@ -288,13 +287,13 @@ public class ImportKeysListFragment extends ListFragment implements
if (error == null) {
// No error
mCachedKeyData = ((ImportKeysListLoader) loader).getParcelableRings();
- } else if (error instanceof ImportKeysListLoader.FileHasNoContent) {
- Notify.showNotify(getActivity(), R.string.error_import_file_no_content, Notify.Style.ERROR);
- } else if (error instanceof ImportKeysListLoader.NonPgpPart) {
+ } else if (error instanceof ImportKeysListLoader.NoValidKeysException) {
+ Notify.showNotify(getActivity(), R.string.error_import_no_valid_keys, Notify.Style.ERROR);
+ } else if (error instanceof ImportKeysListLoader.NonPgpPartException) {
Notify.showNotify(getActivity(),
- ((ImportKeysListLoader.NonPgpPart) error).getCount() + " " + getResources().
+ ((ImportKeysListLoader.NonPgpPartException) error).getCount() + " " + getResources().
getQuantityString(R.plurals.error_import_non_pgp_part,
- ((ImportKeysListLoader.NonPgpPart) error).getCount()),
+ ((ImportKeysListLoader.NonPgpPartException) error).getCount()),
Notify.Style.OK
);
} else {
@@ -308,9 +307,11 @@ public class ImportKeysListFragment extends ListFragment implements
if (error == null) {
// No error
} else if (error instanceof Keyserver.QueryTooShortException) {
- Notify.showNotify(getActivity(), R.string.error_keyserver_insufficient_query, Notify.Style.ERROR);
+ Notify.showNotify(getActivity(), R.string.error_query_too_short, Notify.Style.ERROR);
} else if (error instanceof Keyserver.TooManyResponsesException) {
- Notify.showNotify(getActivity(), R.string.error_keyserver_too_many_responses, Notify.Style.ERROR);
+ Notify.showNotify(getActivity(), R.string.error_too_many_responses, Notify.Style.ERROR);
+ } else if (error instanceof Keyserver.QueryTooShortOrTooManyResponsesException) {
+ Notify.showNotify(getActivity(), R.string.error_too_short_or_too_many_responses, Notify.Style.ERROR);
} else if (error instanceof Keyserver.QueryFailedException) {
Log.d(Constants.TAG,
"Unrecoverable keyserver query error: " + error.getLocalizedMessage());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
index 9cc623c83..50ff5c753 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
@@ -17,29 +17,19 @@
package org.sufficientlysecure.keychain.ui;
-import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
import android.view.Menu;
import android.view.MenuItem;
-import com.devspark.appmsg.AppMsg;
-
-import org.spongycastle.bcpg.sig.KeyFlags;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Constants.choice.algorithm;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
-import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.io.IOException;
@@ -51,11 +41,10 @@ public class KeyListActivity extends DrawerActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // if this is the first time show first time activity
Preferences prefs = Preferences.getPreferences(this);
- if (prefs.getFirstTime()) {
- prefs.setFirstTime(false);
- Intent intent = new Intent(this, FirstTimeActivity.class);
- startActivity(intent);
+ if (prefs.isFirstTime()) {
+ startActivity(new Intent(this, FirstTimeActivity.class));
finish();
return;
}
@@ -85,7 +74,7 @@ public class KeyListActivity extends DrawerActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case R.id.menu_key_list_import:
+ case R.id.menu_key_list_add:
importKeys();
return true;
@@ -93,6 +82,12 @@ public class KeyListActivity extends DrawerActivity {
createKey();
return true;
+ case R.id.menu_key_list_import_existing_key:
+ Intent intentImportExisting = new Intent(this, ImportKeysActivity.class);
+ intentImportExisting.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN);
+ startActivityForResult(intentImportExisting, 0);
+ return true;
+
case R.id.menu_key_list_export:
mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
return true;
@@ -100,25 +95,27 @@ public class KeyListActivity extends DrawerActivity {
case R.id.menu_key_list_debug_read:
try {
KeychainDatabase.debugRead(this);
- AppMsg.makeText(this, "Restored from backup", AppMsg.STYLE_CONFIRM).show();
+ Notify.showNotify(this, "Restored Notify.Style backup", Notify.Style.INFO);
getContentResolver().notifyChange(KeychainContract.KeyRings.CONTENT_URI, null);
} catch (IOException e) {
Log.e(Constants.TAG, "IO Error", e);
- AppMsg.makeText(this, "IO Error: " + e.getMessage(), AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(this, "IO Notify.Style: " + e.getMessage(), Notify.Style.ERROR);
}
return true;
case R.id.menu_key_list_debug_write:
try {
KeychainDatabase.debugWrite(this);
- AppMsg.makeText(this, "Backup successful", AppMsg.STYLE_CONFIRM).show();
- } catch (IOException e) {
+ Notify.showNotify(this, "Backup Notify.Style", Notify.Style.INFO);
+ } catch(IOException e) {
Log.e(Constants.TAG, "IO Error", e);
- AppMsg.makeText(this, "IO Error: " + e.getMessage(), AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(this, "IO Notify.Style: " + e.getMessage(), Notify.Style.ERROR);
}
return true;
case R.id.menu_key_list_debug_first_time:
+ Preferences prefs = Preferences.getPreferences(this);
+ prefs.setFirstTime(true);
Intent intent = new Intent(this, FirstTimeActivity.class);
startActivity(intent);
finish();
@@ -139,4 +136,4 @@ public class KeyListActivity extends DrawerActivity {
startActivity(intent);
}
-} \ No newline at end of file
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index 9d0a80406..aa17aea3d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
+import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -46,14 +47,11 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Button;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
@@ -62,6 +60,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.util.Highlighter;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.util.Date;
import java.util.HashMap;
@@ -86,6 +85,7 @@ public class KeyListFragment extends LoaderFragment
private Button mButtonEmptyCreate;
private Button mButtonEmptyImport;
+ public static final int REQUEST_CODE_CREATE_OR_IMPORT_KEY = 0x00007012;
/**
* Load custom layout with StickyListView from library
@@ -104,11 +104,8 @@ public class KeyListFragment extends LoaderFragment
@Override
public void onClick(View v) {
- Intent intent = new Intent(getActivity(), EditKeyActivityOld.class);
- intent.setAction(EditKeyActivityOld.ACTION_CREATE_KEY);
- intent.putExtra(EditKeyActivityOld.EXTRA_GENERATE_DEFAULT_KEYS, true);
- intent.putExtra(EditKeyActivityOld.EXTRA_USER_IDS, ""); // show user id view
- startActivityForResult(intent, 0);
+ Intent intent = new Intent(getActivity(), CreateKeyActivity.class);
+ startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
}
});
mButtonEmptyImport = (Button) view.findViewById(R.id.key_list_empty_button_import);
@@ -117,8 +114,8 @@ public class KeyListFragment extends LoaderFragment
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE);
- startActivityForResult(intent, 0);
+ intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN);
+ startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY);
}
});
@@ -339,8 +336,8 @@ public class KeyListFragment extends LoaderFragment
public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) {
// Can only work on singular secret keys
if(hasSecret && masterKeyIds.length > 1) {
- AppMsg.makeText(getActivity(), R.string.secret_cannot_multiple,
- AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.secret_cannot_multiple,
+ Notify.Style.ERROR);
return;
}
@@ -437,9 +434,7 @@ public class KeyListFragment extends LoaderFragment
private class ItemViewHolder {
TextView mMainUserId;
TextView mMainUserIdRest;
- FrameLayout mStatusLayout;
- TextView mRevoked;
- ImageView mVerified;
+ ImageView mStatus;
}
@Override
@@ -448,9 +443,7 @@ public class KeyListFragment extends LoaderFragment
ItemViewHolder holder = new ItemViewHolder();
holder.mMainUserId = (TextView) view.findViewById(R.id.mainUserId);
holder.mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- holder.mStatusLayout = (FrameLayout) view.findViewById(R.id.status_layout);
- holder.mRevoked = (TextView) view.findViewById(R.id.revoked);
- holder.mVerified = (ImageView) view.findViewById(R.id.verified);
+ holder.mStatus = (ImageView) view.findViewById(R.id.status_image);
view.setTag(holder);
return view;
}
@@ -482,30 +475,40 @@ public class KeyListFragment extends LoaderFragment
}
}
- { // set edit button and revoked info, specific by key type
-
- if (cursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
- // this is a secret key
- h.mStatusLayout.setVisibility(View.VISIBLE);
- h.mRevoked.setVisibility(View.GONE);
- h.mVerified.setVisibility(View.GONE);
- } else {
- // this is a public key - show if it's revoked
-
- boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
- boolean isExpired = !cursor.isNull(INDEX_EXPIRY)
- && new Date(cursor.getLong(INDEX_EXPIRY)*1000).before(new Date());
- if(isRevoked || isExpired) {
- h.mStatusLayout.setVisibility(View.VISIBLE);
- h.mRevoked.setVisibility(View.VISIBLE);
- h.mVerified.setVisibility(View.GONE);
- h.mRevoked.setText(isRevoked ? R.string.revoked : R.string.expired);
+ { // set edit button and status, specific by key type
+
+ boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
+ boolean isExpired = !cursor.isNull(INDEX_EXPIRY)
+ && new Date(cursor.getLong(INDEX_EXPIRY)*1000).before(new Date());
+ boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
+
+ // Note: order is important!
+ if (isRevoked) {
+ h.mStatus.setImageDrawable(
+ getResources().getDrawable(R.drawable.status_signature_revoked_cutout));
+ h.mStatus.setColorFilter(getResources().getColor(R.color.android_red_dark),
+ PorterDuff.Mode.SRC_ATOP);
+ h.mStatus.setVisibility(View.VISIBLE);
+ } else if (isExpired) {
+ h.mStatus.setImageDrawable(
+ getResources().getDrawable(R.drawable.status_signature_expired_cutout));
+ h.mStatus.setColorFilter(getResources().getColor(R.color.android_orange_dark),
+ PorterDuff.Mode.SRC_ATOP);
+ h.mStatus.setVisibility(View.VISIBLE);
+ } else if (isVerified) {
+ if (cursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
+ // this is a secret key
+ h.mStatus.setVisibility(View.GONE);
} else {
- boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
- h.mStatusLayout.setVisibility(isVerified ? View.VISIBLE : View.GONE);
- h.mRevoked.setVisibility(View.GONE);
- h.mVerified.setVisibility(isVerified ? View.VISIBLE : View.GONE);
+ // this is a public key - show if it's verified
+ h.mStatus.setImageDrawable(
+ getResources().getDrawable(R.drawable.status_signature_verified_cutout));
+ h.mStatus.setColorFilter(getResources().getColor(R.color.android_green_dark),
+ PorterDuff.Mode.SRC_ATOP);
+ h.mStatus.setVisibility(View.VISIBLE);
}
+ } else {
+ h.mStatus.setVisibility(View.GONE);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
index 75c967c60..43de6774b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
@@ -178,9 +178,11 @@ public class LogDisplayFragment extends ListFragment implements OnTouchListener
if (entry.mParameters != null && entry.mParameters.length > 0
&& entry.mParameters[0] instanceof Integer) {
ih.mText.setText(getResources().getQuantityString(entry.mType.getMsgId(),
- (Integer) entry.mParameters[0], entry.mParameters));
+ (Integer) entry.mParameters[0],
+ entry.mParameters));
} else {
- ih.mText.setText(getResources().getString(entry.mType.getMsgId(), entry.mParameters));
+ ih.mText.setText(getResources().getString(entry.mType.getMsgId(),
+ entry.mParameters));
}
ih.mText.setTextColor(entry.mLevel == LogLevel.DEBUG ? Color.GRAY : Color.BLACK);
convertView.setPadding((entry.mIndent) * dipFactor, 0, 0, 0);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeActivity.java
new file mode 100644
index 000000000..a906dfa97
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeActivity.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v7.app.ActionBarActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ActionBarHelper;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
+import org.sufficientlysecure.keychain.util.Notify.Style;
+import org.sufficientlysecure.keychain.util.QrCodeUtils;
+
+public class QrCodeActivity extends ActionBarActivity {
+
+ private ImageView mFingerprintQrCode;
+
+ private static final int QR_CODE_SIZE = 1000;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Inflate a "Done" custom action bar
+ ActionBarHelper.setOneButtonView(getSupportActionBar(),
+ R.string.btn_okay, R.drawable.ic_action_done,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // "Done"
+ finish();
+ }
+ }
+ );
+
+ setContentView(R.layout.qr_code_activity);
+
+ Uri dataUri = getIntent().getData();
+ if (dataUri == null) {
+ Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
+ finish();
+ return;
+ }
+
+ mFingerprintQrCode = (ImageView) findViewById(R.id.qr_code_image);
+
+ mFingerprintQrCode.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finish();
+ }
+ });
+
+ ProviderHelper providerHelper = new ProviderHelper(this);
+ try {
+ byte[] blob = (byte[]) providerHelper.getGenericData(
+ KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
+ KeychainContract.KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+ if (blob == null) {
+ Log.e(Constants.TAG, "key not found!");
+ Notify.showNotify(this, R.string.error_key_not_found, Style.ERROR);
+ finish();
+ }
+
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
+ String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
+ mFingerprintQrCode.setImageBitmap(QrCodeUtils.getQRCodeBitmap(qrCodeContent, QR_CODE_SIZE));
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.e(Constants.TAG, "key not found!", e);
+ Notify.showNotify(this, R.string.error_key_not_found, Style.ERROR);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // custom activity transition to get zoom in effect
+ this.overridePendingTransition(R.anim.qr_code_zoom_enter, android.R.anim.fade_out);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ // custom activity transition to get zoom out effect
+ this.overridePendingTransition(0, R.anim.qr_code_zoom_exit);
+ }
+
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
index dbd1b7507..57bfc7bd5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.util.Log;
@@ -92,7 +93,7 @@ public class UploadKeyActivity extends ActionBarActivity {
intent.setAction(KeychainIntentService.ACTION_UPLOAD_KEYRING);
// set data uri as path to keyring
- Uri blobUri = KeychainContract.KeyRingData.buildPublicKeyRingUri(mDataUri);
+ Uri blobUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
intent.setData(blobUri);
// fill values for this action
@@ -105,7 +106,7 @@ public class UploadKeyActivity extends ActionBarActivity {
// Message is received after uploading is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) {
+ getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
index cfdea0611..5201b5df8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
@@ -35,7 +35,7 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
@@ -143,16 +143,16 @@ public class ViewCertActivity extends ActionBarActivity
try {
ProviderHelper providerHelper = new ProviderHelper(this);
- WrappedPublicKeyRing signeeRing =
- providerHelper.getWrappedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID));
- WrappedPublicKeyRing signerRing =
- providerHelper.getWrappedPublicKeyRing(sig.getKeyId());
+ CanonicalizedPublicKeyRing signeeRing =
+ providerHelper.getCanonicalizedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID));
+ CanonicalizedPublicKeyRing signerRing =
+ providerHelper.getCanonicalizedPublicKeyRing(sig.getKeyId());
try {
sig.init(signerRing.getPublicKey());
if (sig.verifySignature(signeeRing.getPublicKey(), signeeUid)) {
mStatus.setText(R.string.cert_verify_ok);
- mStatus.setTextColor(getResources().getColor(R.color.result_green));
+ mStatus.setTextColor(getResources().getColor(R.color.android_green_light));
} else {
mStatus.setText(R.string.cert_verify_failed);
mStatus.setTextColor(getResources().getColor(R.color.alert));
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index a9cd0976b..44a51a75f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -19,9 +19,9 @@
package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
+import android.graphics.PorterDuff;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
@@ -43,8 +43,9 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
-
-import com.devspark.appmsg.AppMsg;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -54,11 +55,12 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.OperationResults.ImportResult;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout.TabColorizer;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout;
+import org.sufficientlysecure.keychain.util.Notify;
import java.util.Date;
import java.util.HashMap;
@@ -81,11 +83,11 @@ public class ViewKeyActivity extends ActionBarActivity implements
private ViewPager mViewPager;
private SlidingTabLayout mSlidingTabLayout;
private PagerTabStripAdapter mTabsAdapter;
- private View mStatusDivider;
- private View mStatusRevoked;
- private View mStatusExpired;
- public static final int REQUEST_CODE_LOOKUP_KEY = 0x00007006;
+ private LinearLayout mStatusLayout;
+ private TextView mStatusText;
+ private ImageView mStatusImage;
+ private View mStatusDivider;
// NFC
private NfcAdapter mNfcAdapter;
@@ -115,9 +117,10 @@ public class ViewKeyActivity extends ActionBarActivity implements
setContentView(R.layout.view_key_activity);
- mStatusDivider = findViewById(R.id.status_divider);
- mStatusRevoked = findViewById(R.id.view_key_revoked);
- mStatusExpired = findViewById(R.id.view_key_expired);
+ mStatusLayout = (LinearLayout) findViewById(R.id.view_key_status_layout);
+ mStatusText = (TextView) findViewById(R.id.view_key_status_text);
+ mStatusImage = (ImageView) findViewById(R.id.view_key_status_image);
+ mStatusDivider = findViewById(R.id.view_key_status_divider);
mViewPager = (ViewPager) findViewById(R.id.view_key_pager);
mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.view_key_sliding_tab_layout);
@@ -140,20 +143,27 @@ public class ViewKeyActivity extends ActionBarActivity implements
switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB);
}
- Uri dataUri = getDataUri();
- if (dataUri == null) {
- Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
+ mDataUri = getIntent().getData();
+ if (mDataUri == null) {
+ Log.e(Constants.TAG, "Data missing. Should be uri of key!");
finish();
return;
}
+ if (mDataUri.getHost().equals(ContactsContract.AUTHORITY)) {
+ mDataUri = ContactHelper.dataUriFromContactUri(this, mDataUri);
+ }
+
+ Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
- loadData(dataUri);
+ // Prepare the loaders. Either re-connect with an existing ones,
+ // or start new ones.
+ getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
- initNfc(dataUri);
+ initNfc(mDataUri);
mShowAdvancedTabs = false;
- initTabs(dataUri);
+ initTabs(mDataUri);
// switch to tab selected by extra
mViewPager.setCurrentItem(switchToTab);
@@ -230,24 +240,6 @@ public class ViewKeyActivity extends ActionBarActivity implements
mSlidingTabLayout.setViewPager(mViewPager);
}
- private Uri getDataUri() {
- Uri dataUri = getIntent().getData();
- if (dataUri != null && dataUri.getHost().equals(ContactsContract.AUTHORITY)) {
- dataUri = ContactHelper.dataUriFromContactUri(this, dataUri);
- }
- return dataUri;
- }
-
- private void loadData(Uri dataUri) {
- mDataUri = dataUri;
-
- Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
-
- // Prepare the loaders. Either re-connect with an existing ones,
- // or start new ones.
- getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
- }
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -268,14 +260,6 @@ public class ViewKeyActivity extends ActionBarActivity implements
startActivity(homeIntent);
return true;
}
- case R.id.menu_key_view_update: {
- updateFromKeyserver(mDataUri, mProviderHelper);
- return true;
- }
- case R.id.menu_key_view_export_keyserver: {
- uploadToKeyserver(mDataUri);
- return true;
- }
case R.id.menu_key_view_export_file: {
exportToFile(mDataUri, mExportHelper, mProviderHelper);
return true;
@@ -295,7 +279,7 @@ public class ViewKeyActivity extends ActionBarActivity implements
}
}
} catch (ProviderHelper.NotFoundException e) {
- AppMsg.makeText(this, R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR);
Log.e(Constants.TAG, "Key not found", e);
}
return super.onOptionsItemSelected(item);
@@ -317,26 +301,6 @@ public class ViewKeyActivity extends ActionBarActivity implements
);
}
- private void uploadToKeyserver(Uri dataUri) throws ProviderHelper.NotFoundException {
- Intent uploadIntent = new Intent(this, UploadKeyActivity.class);
- uploadIntent.setData(dataUri);
- startActivityForResult(uploadIntent, 0);
- }
-
- private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper)
- throws ProviderHelper.NotFoundException {
- byte[] blob = (byte[]) providerHelper.getGenericData(
- KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
- KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
- String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
-
- Intent queryIntent = new Intent(this, ImportKeysActivity.class);
- queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT);
- queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint);
-
- startActivityForResult(queryIntent, REQUEST_CODE_LOOKUP_KEY);
- }
-
private void deleteKey(Uri dataUri, ExportHelper exportHelper) {
// Message is received after key is deleted
Handler returnHandler = new Handler() {
@@ -352,22 +316,11 @@ public class ViewKeyActivity extends ActionBarActivity implements
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case REQUEST_CODE_LOOKUP_KEY: {
- if (resultCode == Activity.RESULT_OK) {
- ImportResult result = data.getParcelableExtra(ImportKeysActivity.EXTRA_RESULT);
- if (result != null) {
- result.displayNotify(this);
- }
- }
- break;
- }
-
- default: {
- super.onActivityResult(requestCode, resultCode, data);
-
- break;
- }
+ if (data != null && data.hasExtra(OperationResultParcel.EXTRA_RESULT)) {
+ OperationResultParcel result = data.getParcelableExtra(OperationResultParcel.EXTRA_RESULT);
+ result.createNotify(this).show();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
}
}
@@ -455,8 +408,8 @@ public class ViewKeyActivity extends ActionBarActivity implements
public void handleMessage(Message msg) {
switch (msg.what) {
case NFC_SENT:
- AppMsg.makeText(ViewKeyActivity.this, R.string.nfc_successful,
- AppMsg.STYLE_INFO).show();
+ Notify.showNotify(
+ ViewKeyActivity.this, R.string.nfc_successful, Notify.Style.INFO);
break;
}
}
@@ -515,22 +468,32 @@ public class ViewKeyActivity extends ActionBarActivity implements
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId);
getSupportActionBar().setSubtitle(keyIdStr);
- // If this key is revoked, it cannot be used for anything!
- if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) {
+ boolean isRevoked = data.getInt(INDEX_UNIFIED_IS_REVOKED) > 0;
+ boolean isExpired = !data.isNull(INDEX_UNIFIED_EXPIRY)
+ && new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000).before(new Date());
+
+ // Note: order is important
+ if (isRevoked) {
+ mStatusText.setText(R.string.view_key_revoked);
+ mStatusText.setTextColor(getResources().getColor(R.color.android_red_dark));
+ mStatusImage.setImageDrawable(
+ getResources().getDrawable(R.drawable.status_signature_revoked_cutout));
+ mStatusImage.setColorFilter(getResources().getColor(R.color.android_red_dark),
+ PorterDuff.Mode.SRC_ATOP);
+ mStatusDivider.setVisibility(View.VISIBLE);
+ mStatusLayout.setVisibility(View.VISIBLE);
+ } else if (isExpired) {
+ mStatusText.setText(R.string.view_key_expired);
+ mStatusText.setTextColor(getResources().getColor(R.color.android_orange_dark));
+ mStatusImage.setImageDrawable(
+ getResources().getDrawable(R.drawable.status_signature_expired_cutout));
+ mStatusImage.setColorFilter(getResources().getColor(R.color.android_orange_dark),
+ PorterDuff.Mode.SRC_ATOP);
mStatusDivider.setVisibility(View.VISIBLE);
- mStatusRevoked.setVisibility(View.VISIBLE);
- mStatusExpired.setVisibility(View.GONE);
+ mStatusLayout.setVisibility(View.VISIBLE);
} else {
- mStatusRevoked.setVisibility(View.GONE);
-
- Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000);
- if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) {
- mStatusDivider.setVisibility(View.VISIBLE);
- mStatusExpired.setVisibility(View.VISIBLE);
- } else {
- mStatusDivider.setVisibility(View.GONE);
- mStatusExpired.setVisibility(View.GONE);
- }
+ mStatusDivider.setVisibility(View.GONE);
+ mStatusLayout.setVisibility(View.GONE);
}
break;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index f0636cf2c..370a7312f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenKeychain/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.PorterDuff;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
@@ -27,19 +28,21 @@ import android.support.v4.content.Loader;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.ListView;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
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.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import java.util.Date;
@@ -52,7 +55,9 @@ public class ViewKeyMainFragment extends LoaderFragment implements
private View mActionEditDivider;
private View mActionEncrypt;
private View mActionCertify;
- private View mActionCertifyDivider;
+ private View mActionCertifyText;
+ private ImageView mActionCertifyImage;
+ private View mActionUpdate;
private ListView mUserIds;
@@ -76,7 +81,12 @@ public class ViewKeyMainFragment extends LoaderFragment implements
mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider);
mActionEncrypt = view.findViewById(R.id.view_key_action_encrypt);
mActionCertify = view.findViewById(R.id.view_key_action_certify);
- mActionCertifyDivider = view.findViewById(R.id.view_key_action_certify_divider);
+ mActionCertifyText = view.findViewById(R.id.view_key_action_certify_text);
+ mActionCertifyImage = (ImageView) view.findViewById(R.id.view_key_action_certify_image);
+ // make certify image gray, like action icons
+ mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
+ PorterDuff.Mode.SRC_IN);
+ mActionUpdate = view.findViewById(R.id.view_key_action_update);
return root;
}
@@ -116,6 +126,15 @@ public class ViewKeyMainFragment extends LoaderFragment implements
editKey(mDataUri);
}
});
+ mActionUpdate.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View view) {
+ try {
+ updateFromKeyserver(mDataUri, new ProviderHelper(getActivity()));
+ } catch (NotFoundException e) {
+ Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR);
+ }
+ }
+ });
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0);
mUserIds.setAdapter(mUserIdsAdapter);
@@ -182,6 +201,7 @@ public class ViewKeyMainFragment extends LoaderFragment implements
if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) {
mActionEdit.setEnabled(false);
mActionCertify.setEnabled(false);
+ mActionCertifyText.setEnabled(false);
mActionEncrypt.setEnabled(false);
} else {
mActionEdit.setEnabled(true);
@@ -189,9 +209,11 @@ public class ViewKeyMainFragment extends LoaderFragment implements
Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000);
if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) {
mActionCertify.setEnabled(false);
+ mActionCertifyText.setEnabled(false);
mActionEncrypt.setEnabled(false);
} else {
mActionCertify.setEnabled(true);
+ mActionCertifyText.setEnabled(true);
mActionEncrypt.setEnabled(true);
}
}
@@ -225,7 +247,7 @@ public class ViewKeyMainFragment extends LoaderFragment implements
private void encrypt(Uri dataUri) {
// If there is no encryption key, don't bother.
if (!mHasEncrypt) {
- AppMsg.makeText(getActivity(), R.string.error_no_encrypt_subkey, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.error_no_encrypt_subkey, Notify.Style.ERROR);
return;
}
try {
@@ -243,18 +265,30 @@ public class ViewKeyMainFragment extends LoaderFragment implements
}
}
+ private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper)
+ throws ProviderHelper.NotFoundException {
+ byte[] blob = (byte[]) providerHelper.getGenericData(
+ KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
+ KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
+
+ Intent queryIntent = new Intent(getActivity(), ImportKeysActivity.class);
+ queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT);
+ queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint);
+
+ startActivityForResult(queryIntent, 0);
+ }
+
private void certify(Uri dataUri) {
Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class);
signIntent.setData(dataUri);
- startActivity(signIntent);
+ startActivityForResult(signIntent, 0);
}
private void editKey(Uri dataUri) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri));
-// editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
-// startActivityForResult(editIntent, 0);
- startActivity(editIntent);
+ startActivityForResult(editIntent, 0);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java
index 52b573f47..54ab76464 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java
@@ -20,7 +20,14 @@ package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi;
import android.content.Intent;
import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.TransitionDrawable;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
@@ -33,8 +40,6 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import com.devspark.appmsg.AppMsg;
-
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
@@ -44,9 +49,10 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Notify;
import org.sufficientlysecure.keychain.util.QrCodeUtils;
import java.io.IOException;
@@ -65,6 +71,7 @@ public class ViewKeyShareFragment extends LoaderFragment implements
private View mKeyClipboardButton;
private View mNfcHelpButton;
private View mNfcPrefsButton;
+ private View mKeyUploadButton;
ProviderHelper mProviderHelper;
@@ -89,6 +96,7 @@ public class ViewKeyShareFragment extends LoaderFragment implements
mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help);
mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs);
+ mKeyUploadButton = view.findViewById(R.id.view_key_action_upload);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mNfcPrefsButton.setVisibility(View.VISIBLE);
@@ -139,6 +147,12 @@ public class ViewKeyShareFragment extends LoaderFragment implements
showNfcPrefs();
}
});
+ mKeyUploadButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ uploadToKeyserver();
+ }
+ });
return root;
}
@@ -152,7 +166,7 @@ public class ViewKeyShareFragment extends LoaderFragment implements
KeyRings.buildUnifiedKeyRingUri(dataUri),
Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
String fingerprint = PgpKeyHelper.convertFingerprintToHex(data);
- if(!toClipboard){
+ if (!toClipboard) {
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
} else {
content = fingerprint;
@@ -171,13 +185,13 @@ public class ViewKeyShareFragment extends LoaderFragment implements
} else {
message = getResources().getString(R.string.key_copied_to_clipboard);
}
- AppMsg.makeText(getActivity(), message, AppMsg.STYLE_INFO).show();
+ Notify.showNotify(getActivity(), message, Notify.Style.OK);
} else {
// Android will fail with android.os.TransactionTooLargeException if key is too big
// see http://www.lonestarprod.com/?p=34
if (content.length() >= 86389) {
- AppMsg.makeText(getActivity(), R.string.key_too_big_for_sharing,
- AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.key_too_big_for_sharing,
+ Notify.Style.ERROR);
return;
}
@@ -195,19 +209,20 @@ public class ViewKeyShareFragment extends LoaderFragment implements
}
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "error processing key!", e);
- AppMsg.makeText(getActivity(), R.string.error_key_processing, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR);
} catch (IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
- AppMsg.makeText(getActivity(), R.string.error_key_processing, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
- AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
+ Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR);
}
}
private void showQrCodeDialog() {
- ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(mDataUri);
- dialog.show(ViewKeyShareFragment.this.getActivity().getSupportFragmentManager(), "shareQrCodeDialog");
+ Intent qrCodeIntent = new Intent(getActivity(), QrCodeActivity.class);
+ qrCodeIntent.setData(mDataUri);
+ startActivity(qrCodeIntent);
}
private void showNfcHelpDialog() {
@@ -292,10 +307,7 @@ public class ViewKeyShareFragment extends LoaderFragment implements
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
- String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
- mFingerprintQrCode.setImageBitmap(
- QrCodeUtils.getQRCodeBitmap(qrCodeContent, QR_CODE_SIZE)
- );
+ loadQrCode(fingerprint);
break;
}
@@ -311,4 +323,42 @@ public class ViewKeyShareFragment extends LoaderFragment implements
*/
public void onLoaderReset(Loader<Cursor> loader) {
}
+
+ /**
+ * Load QR Code asynchronously and with a fade in animation
+ *
+ * @param fingerprint
+ */
+ private void loadQrCode(final String fingerprint) {
+ AsyncTask<Void, Void, Bitmap> loadTask =
+ new AsyncTask<Void, Void, Bitmap>() {
+ protected Bitmap doInBackground(Void... unused) {
+ String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
+ return QrCodeUtils.getQRCodeBitmap(qrCodeContent, QR_CODE_SIZE);
+ }
+
+ protected void onPostExecute(Bitmap qrCode) {
+ mFingerprintQrCode.setImageBitmap(qrCode);
+
+ // Transition drawable with a transparent drawable and the final bitmap
+ final TransitionDrawable td =
+ new TransitionDrawable(new Drawable[]{
+ new ColorDrawable(Color.TRANSPARENT),
+ new BitmapDrawable(getResources(), qrCode)
+ });
+
+ mFingerprintQrCode.setImageDrawable(td);
+ td.startTransition(200);
+ }
+ };
+
+ loadTask.execute();
+ }
+
+ private void uploadToKeyserver() {
+ Intent uploadIntent = new Intent(getActivity(), UploadKeyActivity.class);
+ uploadIntent.setData(mDataUri);
+ startActivityForResult(uploadIntent, 0);
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
index 99f959035..4971c535c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
@@ -30,20 +30,21 @@ import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import java.io.BufferedInputStream;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
public class ImportKeysListLoader
extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
- public static class FileHasNoContent extends Exception {
-
+ public static class NoValidKeysException extends Exception {
}
- public static class NonPgpPart extends Exception {
+ public static class NonPgpPartException extends Exception {
private int mCount;
- public NonPgpPart(int count) {
+ public NonPgpPartException(int count) {
this.mCount = count;
}
@@ -67,7 +68,6 @@ public class ImportKeysListLoader
@Override
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
-
// This has already been loaded! nvm any further, just return
if (mEntryListWrapper != null) {
return mEntryListWrapper;
@@ -119,9 +119,6 @@ public class ImportKeysListLoader
* @return
*/
private void generateListOfKeyrings(InputData inputData) {
-
- boolean isEmpty = true;
-
PositionAwareInputStream progressIn = new PositionAwareInputStream(
inputData.getInputStream());
@@ -130,27 +127,23 @@ public class ImportKeysListLoader
// armor blocks
BufferedInputStream bufferedInput = new BufferedInputStream(progressIn);
try {
-
- // read all available blocks... (asc files can contain many blocks with BEGIN END)
- while (bufferedInput.available() > 0) {
- // TODO: deal with non-keyring objects?
- List<UncachedKeyRing> rings = UncachedKeyRing.fromStream(bufferedInput);
- for(UncachedKeyRing key : rings) {
- ImportKeysListEntry item = new ImportKeysListEntry(getContext(), key);
- mData.add(item);
- mParcelableRings.put(item.hashCode(), new ParcelableKeyRing(key.getEncoded()));
- isEmpty = false;
- }
+ // parse all keyrings
+ Iterator<UncachedKeyRing> it = UncachedKeyRing.fromStream(bufferedInput);
+ while (it.hasNext()) {
+ UncachedKeyRing ring = it.next();
+ ImportKeysListEntry item = new ImportKeysListEntry(getContext(), ring);
+ mData.add(item);
+ mParcelableRings.put(item.hashCode(), new ParcelableKeyRing(ring.getEncoded()));
}
- } catch (Exception e) {
- Log.e(Constants.TAG, "Exception on parsing key file!", e);
- mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, e);
- }
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException on parsing key file! Return NoValidKeysException!", e);
- if (isEmpty) {
- Log.e(Constants.TAG, "File has no content!", new FileHasNoContent());
+ NoValidKeysException e1 = new NoValidKeysException();
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
- (mData, new FileHasNoContent());
+ (mData, e1);
+ } catch (Exception e) {
+ Log.e(Constants.TAG, "Other Exception on parsing key file!", e);
+ mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, e);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
index 18312660a..6d46f3c8f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
@@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context;
import android.database.Cursor;
+import android.graphics.PorterDuff;
+import android.graphics.Typeface;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
@@ -156,7 +158,10 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
if (isRevoked) {
// set revocation icon (can this even be primary?)
- vVerified.setImageResource(R.drawable.key_certify_revoke);
+ vVerified.setImageResource(R.drawable.status_signature_revoked_cutout);
+ vVerified.setColorFilter(
+ mContext.getResources().getColor(R.color.bg_gray),
+ PorterDuff.Mode.SRC_IN);
// disable and strike through text for revoked user ids
vName.setEnabled(false);
@@ -170,22 +175,33 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
vAddress.setEnabled(true);
vComment.setEnabled(true);
- // verified: has been verified
- // isPrimary: show small star icon for primary user ids
- int verified = cursor.getInt(INDEX_VERIFIED);
- switch (verified) {
+ if (isPrimary) {
+ vName.setTypeface(null, Typeface.BOLD);
+ vAddress.setTypeface(null, Typeface.BOLD);
+ } else {
+ vName.setTypeface(null, Typeface.NORMAL);
+ vAddress.setTypeface(null, Typeface.NORMAL);
+ }
+
+ int isVerified = cursor.getInt(INDEX_VERIFIED);
+ switch (isVerified) {
case Certs.VERIFIED_SECRET:
- vVerified.setImageResource(isPrimary
- ? R.drawable.key_certify_primary_ok_depth0
- : R.drawable.key_certify_ok_depth0);
+ vVerified.setImageResource(R.drawable.status_signature_verified_cutout);
+ vVerified.setColorFilter(
+ mContext.getResources().getColor(R.color.android_green_dark),
+ PorterDuff.Mode.SRC_IN);
break;
case Certs.VERIFIED_SELF:
- vVerified.setImageResource(isPrimary
- ? R.drawable.key_certify_primary_ok_self
- : R.drawable.key_certify_ok_self);
+ vVerified.setImageResource(R.drawable.status_signature_unverified_cutout);
+ vVerified.setColorFilter(
+ mContext.getResources().getColor(R.color.bg_gray),
+ PorterDuff.Mode.SRC_IN);
break;
default:
- vVerified.setImageResource(R.drawable.key_certify_error);
+ vVerified.setImageResource(R.drawable.status_signature_invalid_cutout);
+ vVerified.setColorFilter(
+ mContext.getResources().getColor(R.color.android_red_dark),
+ PorterDuff.Mode.SRC_IN);
break;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
index d723f88af..ef2659cf8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
@@ -33,8 +33,8 @@ import android.support.v4.app.FragmentActivity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
@@ -44,8 +44,8 @@ import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
@@ -62,7 +62,6 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
private Messenger mMessenger;
private EditText mPassphraseEditText;
- private boolean mCanKB;
/**
* Shows passphrase dialog to cache a new passphrase the user enters for using it later for
@@ -102,10 +101,10 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
// check if secret key has a passphrase
if (!(secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none)) {
try {
- if (!new ProviderHelper(context).getWrappedSecretKeyRing(secretKeyId).hasPassphrase()) {
+ if (!new ProviderHelper(context).getCanonicalizedSecretKeyRing(secretKeyId).hasPassphrase()) {
throw new PgpGeneralException("No passphrase! No passphrase dialog needed!");
}
- } catch(ProviderHelper.NotFoundException e) {
+ } catch (ProviderHelper.NotFoundException e) {
throw new PgpGeneralException("Error: Key not found!", e);
}
}
@@ -120,11 +119,6 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
return frag;
}
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
/**
* Creates dialog
*/
@@ -138,7 +132,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
alert.setTitle(R.string.title_authentication);
- final WrappedSecretKeyRing secretRing;
+ final CanonicalizedSecretKeyRing secretRing;
String userId;
if (secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none) {
@@ -147,7 +141,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} else {
try {
ProviderHelper helper = new ProviderHelper(activity);
- secretRing = helper.getWrappedSecretKeyRing(secretKeyId);
+ secretRing = helper.getCanonicalizedSecretKeyRing(secretKeyId);
// yes the inner try/catch block is necessary, otherwise the final variable
// above can't be statically verified to have been set in all cases because
// the catch clause doesn't return.
@@ -165,7 +159,6 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
}
});
alert.setCancelable(false);
- mCanKB = false;
return alert.create();
}
@@ -190,7 +183,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
// Early breakout if we are dealing with a symmetric key
if (secretRing == null) {
PassphraseCacheService.addCachedPassphrase(activity, Constants.key.symmetric,
- passphrase, getString(R.string.passp_cache_notif_pwd));
+ passphrase, getString(R.string.passp_cache_notif_pwd));
// also return passphrase back to activity
Bundle data = new Bundle();
data.putString(MESSAGE_DATA_PASSPHRASE, passphrase);
@@ -198,9 +191,9 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
return;
}
- WrappedSecretKey unlockedSecretKey = null;
+ CanonicalizedSecretKey unlockedSecretKey = null;
- for(WrappedSecretKey clickSecretKey : secretRing.secretKeyIterator()) {
+ for (CanonicalizedSecretKey clickSecretKey : secretRing.secretKeyIterator()) {
try {
boolean unlocked = clickSecretKey.unlock(passphrase);
if (unlocked) {
@@ -232,9 +225,9 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
try {
PassphraseCacheService.addCachedPassphrase(activity, masterKeyId, passphrase,
- secretRing.getPrimaryUserIdWithFallback());
- } catch(PgpGeneralException e) {
- Log.e(Constants.TAG, "adding of a passhrase failed", e);
+ secretRing.getPrimaryUserIdWithFallback());
+ } catch (PgpGeneralException e) {
+ Log.e(Constants.TAG, "adding of a passphrase failed", e);
}
if (unlockedSecretKey.getKeyId() != masterKeyId) {
@@ -258,20 +251,30 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
}
});
- mCanKB = true;
- return alert.show();
- }
+ // Hack to open keyboard.
+ // This is the only method that I found to work across all Android versions
+ // http://turbomanage.wordpress.com/2012/05/02/show-soft-keyboard-automatically-when-edittext-receives-focus/
+ // Notes: * onCreateView can't be used because we want to add buttons to the dialog
+ // * opening in onActivityCreated does not work on Android 4.4
+ mPassphraseEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mPassphraseEditText.post(new Runnable() {
+ @Override
+ public void run() {
+ InputMethodManager imm = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mPassphraseEditText, InputMethodManager.SHOW_IMPLICIT);
+ }
+ });
+ }
+ });
+ mPassphraseEditText.requestFocus();
- @Override
- public void onActivityCreated(Bundle arg0) {
- super.onActivityCreated(arg0);
- if (mCanKB) {
- // request focus and open soft keyboard
- mPassphraseEditText.requestFocus();
- getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
-
- mPassphraseEditText.setOnEditorActionListener(this);
- }
+ mPassphraseEditText.setImeActionLabel(getString(android.R.string.ok), EditorInfo.IME_ACTION_DONE);
+ mPassphraseEditText.setOnEditorActionListener(this);
+
+ return alert.show();
}
@Override
@@ -282,6 +285,27 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
sendMessageToHandler(MESSAGE_CANCEL);
}
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ Log.d(Constants.TAG, "onDismiss");
+
+ // hide keyboard on dismiss
+ hideKeyboard();
+ }
+
+ private void hideKeyboard() {
+ InputMethodManager inputManager = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ //check if no view has focus:
+ View v = getActivity().getCurrentFocus();
+ if (v == null)
+ return;
+
+ inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ }
+
/**
* Associate the "done" button on the soft keyboard with the okay button in the view
*/
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
index 93da48b75..1386ed098 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui.dialog;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Message;
@@ -32,6 +33,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -164,18 +166,50 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
}
});
+ // Hack to open keyboard.
+ // This is the only method that I found to work across all Android versions
+ // http://turbomanage.wordpress.com/2012/05/02/show-soft-keyboard-automatically-when-edittext-receives-focus/
+ // Notes: * onCreateView can't be used because we want to add buttons to the dialog
+ // * opening in onActivityCreated does not work on Android 4.4
+ mPassphraseEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mPassphraseEditText.post(new Runnable() {
+ @Override
+ public void run() {
+ InputMethodManager imm = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mPassphraseEditText, InputMethodManager.SHOW_IMPLICIT);
+ }
+ });
+ }
+ });
+ mPassphraseEditText.requestFocus();
+
+ mPassphraseAgainEditText.setImeActionLabel(getString(android.R.string.ok), EditorInfo.IME_ACTION_DONE);
+ mPassphraseAgainEditText.setOnEditorActionListener(this);
+
return alert.show();
}
@Override
- public void onActivityCreated(Bundle arg0) {
- super.onActivityCreated(arg0);
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
- // request focus and open soft keyboard
- mPassphraseEditText.requestFocus();
- getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ // hide keyboard on dismiss
+ hideKeyboard();
+ }
- mPassphraseAgainEditText.setOnEditorActionListener(this);
+ private void hideKeyboard() {
+ InputMethodManager inputManager = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ //check if no view has focus:
+ View v = getActivity().getCurrentFocus();
+ if (v == null)
+ return;
+
+ inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
/**
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
deleted file mode 100644
index 24608784b..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
+++ /dev/null
@@ -1,111 +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.dialog;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.devspark.appmsg.AppMsg;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.QrCodeUtils;
-
-public class ShareQrCodeDialogFragment extends DialogFragment {
- private static final String ARG_KEY_URI = "uri";
-
- private ImageView mImage;
- private TextView mText;
-
- private static final int QR_CODE_SIZE = 1000;
-
- /**
- * Creates new instance of this dialog fragment
- */
- public static ShareQrCodeDialogFragment newInstance(Uri dataUri) {
- ShareQrCodeDialogFragment frag = new ShareQrCodeDialogFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_KEY_URI, dataUri);
-
- frag.setArguments(args);
-
- return frag;
- }
-
- /**
- * Creates dialog
- */
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Activity activity = getActivity();
-
- Uri dataUri = getArguments().getParcelable(ARG_KEY_URI);
-
- CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(getActivity());
- alert.setTitle(R.string.share_qr_code_dialog_title);
-
- LayoutInflater inflater = activity.getLayoutInflater();
- View view = inflater.inflate(R.layout.share_qr_code_dialog, null);
- alert.setView(view);
-
- mImage = (ImageView) view.findViewById(R.id.share_qr_code_dialog_image);
- mText = (TextView) view.findViewById(R.id.share_qr_code_dialog_text);
-
- ProviderHelper providerHelper = new ProviderHelper(getActivity());
- String content;
- try {
- alert.setPositiveButton(R.string.btn_okay, null);
-
- byte[] blob = (byte[]) providerHelper.getGenericData(
- KeyRings.buildUnifiedKeyRingUri(dataUri),
- KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
- if (blob == null) {
- Log.e(Constants.TAG, "key not found!");
- AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
- return null;
- }
-
- String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
- mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint);
- content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
- setQrCode(content);
- } catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "key not found!", e);
- AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
- return null;
- }
-
- return alert.show();
- }
-
- private void setQrCode(String data) {
- mImage.setImageBitmap(QrCodeUtils.getQRCodeBitmap(data, QR_CODE_SIZE));
- }
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Notify.java
index 67f81fb24..22e3f5d66 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Notify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Notify.java
@@ -29,7 +29,7 @@ import com.github.johnpersano.supertoasts.SuperToast;
*/
public class Notify {
- public static enum Style {OK, WARN, ERROR}
+ public static enum Style {OK, WARN, INFO, ERROR}
/**
* Shows a simple in-layout notification with the CharSequence given as parameter
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java
index 869eea03f..95a259336 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java
@@ -46,13 +46,13 @@ public class ProgressScaler implements Progressable {
public void setProgress(int resourceId, int progress, int max) {
if (mWrapped != null) {
- mWrapped.setProgress(resourceId, progress, mMax);
+ mWrapped.setProgress(resourceId, mFrom + progress * (mTo - mFrom) / max, mMax);
}
}
public void setProgress(int progress, int max) {
if (mWrapped != null) {
- mWrapped.setProgress(progress, max);
+ mWrapped.setProgress(mFrom + progress * (mTo - mFrom) / max, mMax);
}
}
diff --git a/OpenKeychain/src/main/res/anim/frag_slide_in_from_left.xml b/OpenKeychain/src/main/res/anim/frag_slide_in_from_left.xml
new file mode 100644
index 000000000..4a021c676
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/frag_slide_in_from_left.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set>
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="-100%"
+ android:toXDelta="0"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:duration="500" />
+</set> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/anim/frag_slide_in_from_right.xml b/OpenKeychain/src/main/res/anim/frag_slide_in_from_right.xml
new file mode 100644
index 000000000..1329f8bef
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/frag_slide_in_from_right.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set>
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="100%"
+ android:toXDelta="0"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:duration="500" />
+</set> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/anim/frag_slide_out_to_left.xml b/OpenKeychain/src/main/res/anim/frag_slide_out_to_left.xml
new file mode 100644
index 000000000..4e02af2a4
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/frag_slide_out_to_left.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set>
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0"
+ android:toXDelta="-100%"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:duration="500" />
+</set> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/anim/frag_slide_out_to_right.xml b/OpenKeychain/src/main/res/anim/frag_slide_out_to_right.xml
new file mode 100644
index 000000000..7b5f63e0d
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/frag_slide_out_to_right.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set>
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0"
+ android:toXDelta="100%"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:duration="500" />
+</set> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/anim/qr_code_zoom_enter.xml b/OpenKeychain/src/main/res/anim/qr_code_zoom_enter.xml
new file mode 100644
index 000000000..2b95cfba6
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/qr_code_zoom_enter.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator">
+ <scale
+ android:fromXScale="0.5"
+ android:toXScale="1.0"
+ android:fromYScale="0.5"
+ android:toYScale="1.0"
+ android:pivotX="50%p"
+ android:pivotY="50%p"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha
+ android:fromAlpha="0"
+ android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/anim/qr_code_zoom_exit.xml b/OpenKeychain/src/main/res/anim/qr_code_zoom_exit.xml
new file mode 100644
index 000000000..772375739
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/qr_code_zoom_exit.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:zAdjustment="top">
+ <scale
+ android:fromXScale="1.0"
+ android:toXScale="0.5"
+ android:fromYScale="1.0"
+ android:toYScale="0.5"
+ android:pivotX="50%p"
+ android:pivotY="50%p"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/create_key_robot.png b/OpenKeychain/src/main/res/drawable-hdpi/create_key_robot.png
new file mode 100644
index 000000000..acc198fc3
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/create_key_robot.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_error.png b/OpenKeychain/src/main/res/drawable-hdpi/key_certify_error.png
deleted file mode 100644
index 391d1c988..000000000
--- a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_error.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_depth0.png b/OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_depth0.png
deleted file mode 100644
index 76944469c..000000000
--- a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_self.png b/OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_self.png
deleted file mode 100644
index 815701015..000000000
--- a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_depth0.png b/OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_depth0.png
deleted file mode 100644
index 026869c14..000000000
--- a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_self.png b/OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_self.png
deleted file mode 100644
index 12d2e026e..000000000
--- a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_primary_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_revoke.png b/OpenKeychain/src/main/res/drawable-hdpi/key_certify_revoke.png
deleted file mode 100644
index c39d3a87c..000000000
--- a/OpenKeychain/src/main/res/drawable-hdpi/key_certify_revoke.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_lock_closed.png b/OpenKeychain/src/main/res/drawable-hdpi/status_lock_closed.png
new file mode 100644
index 000000000..a1b090630
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_lock_closed.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_lock_error.png b/OpenKeychain/src/main/res/drawable-hdpi/status_lock_error.png
new file mode 100644
index 000000000..e567055aa
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_lock_error.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_lock_open.png b/OpenKeychain/src/main/res/drawable-hdpi/status_lock_open.png
new file mode 100644
index 000000000..98e32eadc
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_lock_open.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired.png
new file mode 100644
index 000000000..21e8b536a
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired_cutout.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired_cutout.png
new file mode 100644
index 000000000..84ac9bec2
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_expired_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid.png
new file mode 100644
index 000000000..9ae2a09ab
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid_cutout.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid_cutout.png
new file mode 100644
index 000000000..967e00e80
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_invalid_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked.png
new file mode 100644
index 000000000..16e1d7181
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked_cutout.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked_cutout.png
new file mode 100644
index 000000000..244dd0708
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_revoked_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown.png
new file mode 100644
index 000000000..5c3ba866d
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown_cutout.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown_cutout.png
new file mode 100644
index 000000000..82cc25a4b
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unknown_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified.png
new file mode 100644
index 000000000..b8b472a5a
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified_cutout.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified_cutout.png
new file mode 100644
index 000000000..e752eaeab
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_unverified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified.png
new file mode 100644
index 000000000..d8141b47b
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified_cutout.png b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified_cutout.png
new file mode 100644
index 000000000..08a9f464c
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/status_signature_verified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_error.png b/OpenKeychain/src/main/res/drawable-ldpi/key_certify_error.png
deleted file mode 100644
index 79fddf78a..000000000
--- a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_error.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_depth0.png b/OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_depth0.png
deleted file mode 100644
index c400a1820..000000000
--- a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_self.png b/OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_self.png
deleted file mode 100644
index fb1654b53..000000000
--- a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_revoke.png b/OpenKeychain/src/main/res/drawable-ldpi/key_certify_revoke.png
deleted file mode 100644
index 5228a4b6b..000000000
--- a/OpenKeychain/src/main/res/drawable-ldpi/key_certify_revoke.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/create_key_robot.png b/OpenKeychain/src/main/res/drawable-mdpi/create_key_robot.png
new file mode 100644
index 000000000..58476bfc9
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/create_key_robot.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_error.png b/OpenKeychain/src/main/res/drawable-mdpi/key_certify_error.png
deleted file mode 100644
index 6def8769f..000000000
--- a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_error.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_depth0.png b/OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_depth0.png
deleted file mode 100644
index e16ec810a..000000000
--- a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_self.png b/OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_self.png
deleted file mode 100644
index 715a16487..000000000
--- a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_depth0.png b/OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_depth0.png
deleted file mode 100644
index c376a2897..000000000
--- a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_self.png b/OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_self.png
deleted file mode 100644
index 45a261b24..000000000
--- a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_primary_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_revoke.png b/OpenKeychain/src/main/res/drawable-mdpi/key_certify_revoke.png
deleted file mode 100644
index 62ee0ca42..000000000
--- a/OpenKeychain/src/main/res/drawable-mdpi/key_certify_revoke.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_lock_closed.png b/OpenKeychain/src/main/res/drawable-mdpi/status_lock_closed.png
new file mode 100644
index 000000000..cfc39f0e7
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_lock_closed.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_lock_error.png b/OpenKeychain/src/main/res/drawable-mdpi/status_lock_error.png
new file mode 100644
index 000000000..824dc2672
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_lock_error.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_lock_open.png b/OpenKeychain/src/main/res/drawable-mdpi/status_lock_open.png
new file mode 100644
index 000000000..9bca59ae3
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_lock_open.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired.png
new file mode 100644
index 000000000..81a900147
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired_cutout.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired_cutout.png
new file mode 100644
index 000000000..bc91094b5
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_expired_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid.png
new file mode 100644
index 000000000..baa78f795
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid_cutout.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid_cutout.png
new file mode 100644
index 000000000..bc2f56e2a
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_invalid_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked.png
new file mode 100644
index 000000000..7cf985274
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked_cutout.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked_cutout.png
new file mode 100644
index 000000000..2d2593194
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_revoked_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown.png
new file mode 100644
index 000000000..3d4665320
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown_cutout.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown_cutout.png
new file mode 100644
index 000000000..0fc74d07e
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unknown_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified.png
new file mode 100644
index 000000000..8348b32b3
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified_cutout.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified_cutout.png
new file mode 100644
index 000000000..96a2d1413
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_unverified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified.png
new file mode 100644
index 000000000..02e53ac8a
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified_cutout.png b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified_cutout.png
new file mode 100644
index 000000000..9f7cf837c
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/status_signature_verified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/create_key_robot.png b/OpenKeychain/src/main/res/drawable-xhdpi/create_key_robot.png
new file mode 100644
index 000000000..022f2dd2e
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/create_key_robot.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_error.png b/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_error.png
deleted file mode 100644
index 8278ce2b6..000000000
--- a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_error.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_depth0.png b/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_depth0.png
deleted file mode 100644
index e2aef1177..000000000
--- a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_self.png b/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_self.png
deleted file mode 100644
index 9bb6ceffa..000000000
--- a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_depth0.png b/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_depth0.png
deleted file mode 100644
index de6614246..000000000
--- a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_self.png b/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_self.png
deleted file mode 100644
index ce10da099..000000000
--- a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_primary_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_revoke.png b/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_revoke.png
deleted file mode 100644
index 1478e726b..000000000
--- a/OpenKeychain/src/main/res/drawable-xhdpi/key_certify_revoke.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_closed.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_closed.png
new file mode 100644
index 000000000..7c6bb2d18
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_closed.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_error.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_error.png
new file mode 100644
index 000000000..da4a5d89a
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_error.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_open.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_open.png
new file mode 100644
index 000000000..cd02fc1e4
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_lock_open.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired.png
new file mode 100644
index 000000000..f5105c1ae
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout.png
new file mode 100644
index 000000000..83f6fde35
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid.png
new file mode 100644
index 000000000..67880d6db
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid_cutout.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid_cutout.png
new file mode 100644
index 000000000..29830f5ba
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_invalid_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked.png
new file mode 100644
index 000000000..2ed67419b
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked_cutout.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked_cutout.png
new file mode 100644
index 000000000..2f7695043
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_revoked_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown.png
new file mode 100644
index 000000000..a6f1f2792
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown_cutout.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown_cutout.png
new file mode 100644
index 000000000..2ce28c7ca
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unknown_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified.png
new file mode 100644
index 000000000..c25a84b4d
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified_cutout.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified_cutout.png
new file mode 100644
index 000000000..442c55eee
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_unverified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified.png
new file mode 100644
index 000000000..6f435a85e
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified_cutout.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified_cutout.png
new file mode 100644
index 000000000..160ec7cbe
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_verified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/create_key_robot.png b/OpenKeychain/src/main/res/drawable-xxhdpi/create_key_robot.png
new file mode 100644
index 000000000..5392deafd
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/create_key_robot.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_error.png b/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_error.png
deleted file mode 100644
index 9416720eb..000000000
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_error.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_depth0.png b/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_depth0.png
deleted file mode 100644
index 501a75d63..000000000
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_self.png b/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_self.png
deleted file mode 100644
index 72ada9c1f..000000000
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_depth0.png b/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_depth0.png
deleted file mode 100644
index 1b52ef04d..000000000
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_depth0.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_self.png b/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_self.png
deleted file mode 100644
index baa1c00d2..000000000
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_primary_ok_self.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_revoke.png b/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_revoke.png
deleted file mode 100644
index 217f4e914..000000000
--- a/OpenKeychain/src/main/res/drawable-xxhdpi/key_certify_revoke.png
+++ /dev/null
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_closed.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_closed.png
new file mode 100644
index 000000000..5a9664d59
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_closed.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_error.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_error.png
new file mode 100644
index 000000000..608f065af
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_error.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_open.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_open.png
new file mode 100644
index 000000000..ee34dd396
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_lock_open.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired.png
new file mode 100644
index 000000000..f475c9d84
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired_cutout.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired_cutout.png
new file mode 100644
index 000000000..33a3efed1
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_expired_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid.png
new file mode 100644
index 000000000..f21c2cf52
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid_cutout.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid_cutout.png
new file mode 100644
index 000000000..bc39d3496
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_invalid_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked.png
new file mode 100644
index 000000000..be1a1d9dc
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked_cutout.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked_cutout.png
new file mode 100644
index 000000000..58929661f
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_revoked_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown.png
new file mode 100644
index 000000000..841cfa958
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown_cutout.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown_cutout.png
new file mode 100644
index 000000000..3020357a4
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unknown_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified.png
new file mode 100644
index 000000000..525d1cf6b
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified_cutout.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified_cutout.png
new file mode 100644
index 000000000..3829bb3a0
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_unverified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified.png
new file mode 100644
index 000000000..54eee5ba0
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified_cutout.png b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified_cutout.png
new file mode 100644
index 000000000..3548ee2b6
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/status_signature_verified_cutout.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/layout/api_account_settings_activity.xml b/OpenKeychain/src/main/res/layout/api_account_settings_activity.xml
index 3557c1f00..b2a9c11f5 100644
--- a/OpenKeychain/src/main/res/layout/api_account_settings_activity.xml
+++ b/OpenKeychain/src/main/res/layout/api_account_settings_activity.xml
@@ -1,20 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout
+ <include layout="@layout/notify_area" />
+
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="16dp"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <fragment
- android:id="@+id/api_account_settings_fragment"
- android:name="org.sufficientlysecure.keychain.remote.ui.AccountSettingsFragment"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ 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>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml b/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml
index 49c4ccbfe..1c09820a9 100644
--- a/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml
+++ b/OpenKeychain/src/main/res/layout/api_app_settings_activity.xml
@@ -1,33 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout
+ <include layout="@layout/notify_area" />
+
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="16dp"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <fragment
- android:id="@+id/api_app_settings_fragment"
- android:name="org.sufficientlysecure.keychain.remote.ui.AppSettingsFragment"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:layout="@layout/api_app_settings_fragment" />
+ android:padding="16dp"
+ android:orientation="vertical">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/api_settings_accounts"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ <fragment
+ android:id="@+id/api_app_settings_fragment"
+ 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" />
- <FrameLayout
- android:id="@+id/api_accounts_list_fragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" />
+ <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>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/certify_key_activity.xml b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
index bb43fa805..34d4dbd57 100644
--- a/OpenKeychain/src/main/res/layout/certify_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/certify_key_activity.xml
@@ -1,171 +1,192 @@
<?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"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="wrap_content"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:orientation="vertical">
+ <include layout="@layout/notify_area" />
- <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_certification_key" />
+ <ScrollView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
- <fragment
- android:id="@+id/sign_key_select_key_fragment"
- android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- tools:layout="@layout/select_secret_key_layout_fragment" />
-
- <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_key_to_certify" />
-
- <TableLayout
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:layout_marginLeft="8dp"
- 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" />
-
- </TableRow>
-
- <TableRow
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="vertical">
+
+ <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_certification_key" />
+
+ <fragment
+ android:id="@+id/sign_key_select_key_fragment"
+ android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp"
+ tools:layout="@layout/select_secret_key_layout_fragment" />
+
+ <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_key_to_certify" />
+
+ <TableLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_marginLeft="8dp"
+ 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" />
+
+ </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/view_key_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_marginTop="14dp"
+ android:text="@string/section_uids_to_certify" />
+
+ <org.sufficientlysecure.keychain.ui.widget.FixedListView
+ android:id="@+id/view_key_user_ids"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:descendantFocusability="blocksDescendants" />
+
+ <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
+ android:id="@+id/sign_key_upload_checkbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp"
+ android:checked="false"
+ android:text="@string/label_send_key" />
+
+ <Spinner
+ android:id="@+id/upload_key_keyserver"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp"
+ android:enabled="false" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_actions"
+ android:layout_weight="1" />
+
+ <LinearLayout
+ android:id="@+id/certify_key_certify_button"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ android:paddingRight="4dp"
+ android:layout_marginBottom="8dp"
+ style="@style/SelectableItem"
+ android:orientation="horizontal">
<TextView
+ android:paddingLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:text="@string/key_view_action_certify"
+ android:layout_weight="1"
+ android:gravity="center_vertical" />
+
+ <ImageView
+ android:id="@+id/certify_key_action_certify_image"
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/view_key_fingerprint"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:typeface="monospace" />
-
- </TableRow>
+ android:layout_height="match_parent"
+ android:padding="8dp"
+ android:src="@drawable/status_signature_verified_cutout"
+ android:layout_gravity="center_vertical" />
- </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_certify" />
+ </LinearLayout>
- <org.sufficientlysecure.keychain.ui.widget.FixedListView
- android:id="@+id/view_key_user_ids"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:descendantFocusability="blocksDescendants" />
- <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" />
+ </LinearLayout>
- <CheckBox
- android:id="@+id/sign_key_upload_checkbox"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- android:checked="false"
- android:text="@string/label_send_key" />
+ </ScrollView>
- <Spinner
- android:id="@+id/upload_key_keyserver"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- android:enabled="false" />
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_marginTop="14dp"
- android:text="@string/section_actions"
- android:layout_weight="1" />
-
- <TextView
- android:id="@+id/sign_key_sign_button"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:layout_marginBottom="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="@string/key_view_action_certify"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawableRight="@drawable/ic_action_good"
- android:drawablePadding="8dp"
- android:gravity="center_vertical"
- android:clickable="true"
- style="@style/SelectableItem" />
-
- </LinearLayout>
-
-</ScrollView> \ No newline at end of file
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_key_activity.xml b/OpenKeychain/src/main/res/layout/create_key_activity.xml
index 673f43084..0bd053c49 100644
--- a/OpenKeychain/src/main/res/layout/create_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_activity.xml
@@ -1,54 +1,15 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?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="wrap_content"
- android:padding="8dp"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="4dp"
- android:text="Enter Full Name, Email and Passphrase!"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <AutoCompleteTextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="textPersonName"
- android:hint="Name"
- android:ems="10"
- android:id="@+id/name" />
-
- <AutoCompleteTextView
- android:id="@+id/email"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="bla@example.com"
- android:layout_weight="1"
- android:ems="10"
- android:inputType="textEmailAddress" />
+ <include layout="@layout/notify_area" />
- <EditText
+ <FrameLayout
+ android:id="@+id/create_key_fragment_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="textPassword"
- android:hint="passphrase"
- android:ems="10"
- android:id="@+id/passphrase"
- android:layout_gravity="center_horizontal" />
-
-
- <Button
- android:id="@+id/create_key_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_horizontal"
- android:layout_margin="8dp"
- android:text="@string/first_time_create_key"
- android:background="@drawable/button_edgy"
- android:drawableLeft="@drawable/ic_action_new_account" />
-
+ android:layout_height="match_parent"
+ android:orientation="vertical" />
</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
new file mode 100644
index 000000000..6814cd259
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_above="@+id/create_key_buttons_divider">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp"
+ android:text="@string/create_key_final_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="2dp"
+ android:text="@string/label_name"
+ android:textColor="@color/tertiary_text_light"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:layout_marginLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="2dp"
+ android:text="@string/label_email"
+ android:textColor="@color/tertiary_text_light"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <TextView
+ android:id="@+id/email"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginBottom="8dp"
+ android:layout_marginLeft="8dp" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <CheckBox
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/create_key_upload"
+ android:id="@+id/create_key_upload" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="8dp"
+ android:text="@string/create_key_final_robot_text"
+ android:textColor="@color/android_green_dark"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:drawableLeft="@drawable/create_key_robot"
+ android:drawablePadding="8dp" />
+
+ </LinearLayout>
+ </ScrollView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:id="@+id/create_key_buttons">
+
+ <TextView
+ android:id="@+id/create_key_back_button"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/btn_back"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ style="@style/SelectableItem"
+ android:layout_gravity="center_vertical" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/create_key_create_button"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/btn_create_key"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:drawableRight="@drawable/ic_action_new_account"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ style="@style/SelectableItem"
+ android:layout_gravity="center_vertical" />
+ </LinearLayout>
+
+ <View
+ android:id="@+id/create_key_buttons_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider"
+ android:layout_alignTop="@+id/create_key_buttons"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/create_key_input_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_input_fragment.xml
new file mode 100644
index 000000000..588cbb050
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/create_key_input_fragment.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="false"
+ android:layout_above="@+id/create_key_button_divider">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@string/create_key_text" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/label_user_id" />
+
+ <AutoCompleteTextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:imeOptions="actionNext"
+ android:inputType="textPersonName"
+ android:hint="@string/create_key_hint_full_name"
+ android:ems="10"
+ android:id="@+id/name" />
+
+ <AutoCompleteTextView
+ android:id="@+id/email"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:imeOptions="actionNext"
+ android:hint="@string/label_email"
+ android:ems="10"
+ android:inputType="textEmailAddress" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/label_passphrase" />
+
+ <EditText
+ android:id="@+id/passphrase"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:inputType="textPassword"
+ android:hint="@string/label_passphrase"
+ android:ems="10"
+ android:layout_gravity="center_horizontal" />
+
+ <EditText
+ android:id="@+id/passphrase_again"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:inputType="textPassword"
+ android:hint="@string/label_passphrase_again"
+ android:ems="10"
+ android:layout_gravity="center_horizontal" />
+
+ </LinearLayout>
+ </ScrollView>
+
+ <View
+ android:id="@+id/create_key_button_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:background="?android:attr/listDivider"
+ android:layout_alignTop="@+id/create_key_buttons"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:id="@+id/create_key_buttons">
+
+ <TextView
+ android:id="@+id/create_key_back_button"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text=""
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/create_key_button"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/btn_next"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:drawableRight="@drawable/ic_action_new_account"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ style="@style/SelectableItem"
+ android:layout_gravity="center_vertical" />
+ </LinearLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml
index 05877656b..fcad91df3 100644
--- a/OpenKeychain/src/main/res/layout/decrypt_result_include.xml
+++ b/OpenKeychain/src/main/res/layout/decrypt_result_include.xml
@@ -8,7 +8,7 @@
android:paddingRight="16dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
- android:background="@color/result_purple">
+ android:background="@color/android_purple_light">
<View
android:layout_width="match_parent"
diff --git a/OpenKeychain/src/main/res/layout/edit_key_activity.xml b/OpenKeychain/src/main/res/layout/edit_key_activity.xml
index b6c5a1c9a..7e71ccf53 100644
--- a/OpenKeychain/src/main/res/layout/edit_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/edit_key_activity.xml
@@ -1,46 +1,15 @@
<?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:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:fillViewport="true"
- android:orientation="vertical" >
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="16dp"
- android:paddingRight="16dp" >
+ <include layout="@layout/notify_area"/>
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="4dp"
- android:text="@string/label_passphrase" />
+ <FrameLayout
+ android:id="@+id/edit_key_fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" />
- <CheckBox
- android:id="@+id/edit_key_no_passphrase"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_no_passphrase" />
-
- <Button
- android:id="@+id/edit_key_btn_change_passphrase"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:padding="4dp"
- android:text="@string/btn_set_passphrase"
- android:drawableLeft="@drawable/ic_action_edit"
- android:background="@drawable/button_edgy" />
-
- <LinearLayout
- android:id="@+id/edit_key_container"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- </LinearLayout>
- </LinearLayout>
-
-</ScrollView> \ No newline at end of file
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml b/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml
index 856bef36a..a4258b998 100644
--- a/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml
+++ b/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml
@@ -9,7 +9,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="10dp"
- android:background="@color/result_green" />
+ android:background="@color/android_green_light" />
<TableLayout
android:layout_width="0dp"
diff --git a/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml b/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml
index e69452db1..ef0e2626e 100644
--- a/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml
+++ b/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml
@@ -10,7 +10,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="10dp"
- android:background="@color/result_green" />
+ android:background="@color/android_green_light" />
<LinearLayout
android:orientation="vertical"
diff --git a/OpenKeychain/src/main/res/layout/first_time_activity.xml b/OpenKeychain/src/main/res/layout/first_time_activity.xml
index 514f34212..2d750c1a7 100644
--- a/OpenKeychain/src/main/res/layout/first_time_activity.xml
+++ b/OpenKeychain/src/main/res/layout/first_time_activity.xml
@@ -2,18 +2,100 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="16dp"
- android:paddingBottom="8dp">
+ android:paddingTop="16dp">
<LinearLayout
+ android:id="@+id/first_time_buttons"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:layout_alignParentBottom="true"
android:orientation="vertical">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/first_time_import_key"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/first_time_import_key"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:drawableRight="@drawable/ic_action_collection"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ android:clickable="true"
+ style="@style/SelectableItem" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/first_time_create_key"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/first_time_create_key"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:drawableRight="@drawable/ic_action_new_account"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ android:clickable="true"
+ style="@style/SelectableItem" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/first_time_cancel"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/first_time_skip"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center"
+ android:clickable="true"
+ style="@style/SelectableItem"
+ android:layout_gravity="center_horizontal" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:layout_above="@+id/first_time_buttons">
+
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/app_name"
android:drawableLeft="@drawable/ic_launcher"
@@ -23,12 +105,15 @@
<ImageView
android:layout_width="wrap_content"
- android:layout_marginLeft="64dp"
- android:layout_marginRight="64dp"
+ android:layout_height="0dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
- android:layout_height="256dp"
- android:src="@drawable/first_time_1" />
+ android:adjustViewBounds="true"
+ android:src="@drawable/first_time_1"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1" />
<TextView
android:layout_width="wrap_content"
@@ -38,51 +123,9 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/first_time_text1"
android:layout_gravity="center_horizontal"
- android:gravity="center_horizontal" />
+ android:gravity="center_horizontal"
+ android:layout_marginBottom="16dp" />
-
- </LinearLayout>
-
- <Button
- android:id="@+id/first_time_cancel"
- android:layout_alignParentBottom="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:text="@string/first_time_skip"
- android:background="@drawable/button_edgy" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/first_time_cancel"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/first_time_create_key"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_weight="1"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:text="@string/first_time_create_key"
- android:background="@drawable/button_edgy"
- android:drawableLeft="@drawable/ic_action_new_account" />
-
- <Button
- android:id="@+id/first_time_import_key"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_horizontal"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:text="@string/first_time_import_key"
- android:background="@drawable/button_edgy"
- android:drawableLeft="@drawable/ic_action_download" />
</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/key_list_activity.xml b/OpenKeychain/src/main/res/layout/key_list_activity.xml
index c4c2c35cb..297fc526e 100644
--- a/OpenKeychain/src/main/res/layout/key_list_activity.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_activity.xml
@@ -2,9 +2,18 @@
<android.support.v4.widget.FixedDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent">
- <include layout="@layout/key_list_content"/>
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/notify_area" />
+
+ <include layout="@layout/key_list_content" />
+
+ </LinearLayout>
<include layout="@layout/drawer_list" />
diff --git a/OpenKeychain/src/main/res/layout/key_list_fragment.xml b/OpenKeychain/src/main/res/layout/key_list_fragment.xml
index 32b77baac..f1da19b72 100644
--- a/OpenKeychain/src/main/res/layout/key_list_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_fragment.xml
@@ -56,6 +56,7 @@
android:textSize="14sp"
android:text="@string/key_list_empty_button_create"
android:drawableLeft="@drawable/ic_action_new_account"
+ android:drawablePadding="8dp"
android:background="@drawable/button_edgy"/>
<TextView
@@ -73,7 +74,8 @@
android:layout_margin="4dp"
android:textSize="14sp"
android:text="@string/key_list_empty_button_import"
- android:drawableLeft="@drawable/ic_action_download"
+ android:drawableLeft="@drawable/ic_action_collection"
+ android:drawablePadding="8dp"
android:background="@drawable/button_edgy" />
</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/key_list_header.xml b/OpenKeychain/src/main/res/layout/key_list_header.xml
index 8cb0d4262..4809fc5ab 100644
--- a/OpenKeychain/src/main/res/layout/key_list_header.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_header.xml
@@ -21,7 +21,7 @@
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="8dp"
- android:visibility="visible"
+ android:visibility="gone"
android:textColor="@android:color/darker_gray" />
</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/key_list_item.xml b/OpenKeychain/src/main/res/layout/key_list_item.xml
index 99e4c0268..8d600464c 100644
--- a/OpenKeychain/src/main/res/layout/key_list_item.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_item.xml
@@ -38,30 +38,12 @@
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
- <FrameLayout
- android:id="@+id/status_layout"
+ <ImageView
android:layout_width="wrap_content"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/revoked"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="end"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:text="@string/revoked"
- android:textColor="#e00"
- android:layout_gravity="center"
- android:padding="12dp" />
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/verified"
- android:layout_gravity="center"
- android:src="@drawable/key_certify_ok_depth0"
- android:padding="16dp" />
- </FrameLayout>
+ android:layout_height="wrap_content"
+ android:id="@+id/status_image"
+ android:layout_gravity="center"
+ android:src="@drawable/status_signature_revoked_cutout"
+ android:padding="16dp" />
</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/notify_area.xml b/OpenKeychain/src/main/res/layout/notify_area.xml
index d1ba265a5..43df1cde8 100644
--- a/OpenKeychain/src/main/res/layout/notify_area.xml
+++ b/OpenKeychain/src/main/res/layout/notify_area.xml
@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/card_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/emphasis"
android:orientation="vertical" />
</merge> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/edit_key_activity_new.xml b/OpenKeychain/src/main/res/layout/qr_code_activity.xml
index f96b993c5..57c869db6 100644
--- a/OpenKeychain/src/main/res/layout/edit_key_activity_new.xml
+++ b/OpenKeychain/src/main/res/layout/qr_code_activity.xml
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <FrameLayout
- android:id="@+id/edit_key_fragment_container"
+ <ImageView
+ android:id="@+id/qr_code_image"
+ android:padding="32dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical" />
+ style="@style/SelectableItem" />
</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/share_qr_code_dialog.xml b/OpenKeychain/src/main/res/layout/share_qr_code_dialog.xml
deleted file mode 100644
index 0b58ae72f..000000000
--- a/OpenKeychain/src/main/res/layout/share_qr_code_dialog.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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:orientation="vertical" >
-
- <TextView
- android:id="@+id/share_qr_code_dialog_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="8dp"
- android:textAppearance="@android:style/TextAppearance.Medium" />
-
- <ImageView
- android:id="@+id/share_qr_code_dialog_image"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/upload_key_activity.xml b/OpenKeychain/src/main/res/layout/upload_key_activity.xml
index 5a6f732d5..736617ba5 100644
--- a/OpenKeychain/src/main/res/layout/upload_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/upload_key_activity.xml
@@ -1,55 +1,62 @@
<?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"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout
+ <include layout="@layout/notify_area" />
+
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:orientation="vertical">
-
- <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_key_server" />
+ android:layout_height="match_parent">
- <Spinner
- android:id="@+id/upload_key_keyserver"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp" />
-
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_marginTop="14dp"
- android:text="@string/section_actions"
- android:layout_weight="1" />
-
- <TextView
- android:id="@+id/upload_key_action_upload"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:layout_marginBottom="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="@string/btn_export_to_server"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawableRight="@drawable/ic_action_upload"
- android:drawablePadding="8dp"
- android:gravity="center_vertical"
- android:clickable="true"
- style="@style/SelectableItem" />
-
- </LinearLayout>
-
-</ScrollView> \ No newline at end of file
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="vertical">
+
+ <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_key_server" />
+
+ <Spinner
+ android:id="@+id/upload_key_keyserver"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_marginTop="4dp" />
+
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_marginTop="14dp"
+ android:text="@string/section_actions"
+ android:layout_weight="1" />
+
+ <TextView
+ android:id="@+id/upload_key_action_upload"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_marginBottom="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/btn_export_to_server"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:drawableRight="@drawable/ic_action_upload"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ style="@style/SelectableItem" />
+
+ </LinearLayout>
+
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/view_key_activity.xml b/OpenKeychain/src/main/res/layout/view_key_activity.xml
index 481b1ddf5..b15a73c0e 100644
--- a/OpenKeychain/src/main/res/layout/view_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_activity.xml
@@ -4,42 +4,38 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <LinearLayout
- android:id="@+id/card_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" />
+ <include layout="@layout/notify_area"/>
- <TextView
- android:layout_width="match_parent"
+ <LinearLayout
+ android:id="@+id/view_key_status_layout"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="This key is expired!"
- android:id="@+id/view_key_expired"
- android:textColor="@color/alert"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:gravity="center_vertical|center_horizontal"
+ android:layout_gravity="center"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
- android:visibility="gone" />
+ android:orientation="horizontal">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="This key has been revoked!"
- android:id="@+id/view_key_revoked"
- android:textColor="@color/alert"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:gravity="center_vertical|center_horizontal"
- android:visibility="gone"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp" />
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/view_key_status_image" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/view_key_status_text"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="8dp"/>
+
+ </LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:background="?android:attr/listDivider"
android:visibility="gone"
- android:id="@+id/status_divider" />
+ android:id="@+id/view_key_status_divider" />
<org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout
android:id="@+id/view_key_sliding_tab_layout"
diff --git a/OpenKeychain/src/main/res/layout/view_key_main_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_main_fragment.xml
index d93420a99..7a54fab05 100644
--- a/OpenKeychain/src/main/res/layout/view_key_main_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_main_fragment.xml
@@ -17,7 +17,6 @@
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:layout_marginBottom="4dp"
android:layout_marginTop="8dp"
android:text="@string/section_user_ids"
android:layout_weight="1" />
@@ -35,20 +34,34 @@
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
- <TextView
+ <LinearLayout
android:id="@+id/view_key_action_certify"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="@string/key_view_action_certify"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawableRight="@drawable/ic_action_good"
- android:drawablePadding="8dp"
- android:gravity="center_vertical"
+ android:layout_height="?android:attr/listPreferredItemHeight"
android:clickable="true"
- style="@style/SelectableItem" />
+ android:paddingRight="4dp"
+ style="@style/SelectableItem"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/view_key_action_certify_text"
+ android:paddingLeft="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:text="@string/key_view_action_certify"
+ android:layout_weight="1"
+ android:gravity="center_vertical" />
+
+ <ImageView
+ android:id="@+id/view_key_action_certify_image"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:padding="8dp"
+ android:src="@drawable/status_signature_verified_cutout"
+ android:layout_gravity="center_vertical" />
+
+ </LinearLayout>
<TextView
style="@style/SectionHeader"
@@ -84,7 +97,6 @@
android:id="@+id/view_key_action_encrypt"
android:paddingLeft="8dp"
android:paddingRight="8dp"
- android:layout_marginBottom="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -97,6 +109,28 @@
android:drawablePadding="8dp"
android:gravity="center_vertical" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/view_key_action_update"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_marginBottom="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ style="@style/SelectableItem"
+ android:text="@string/key_view_action_update"
+ android:layout_weight="1"
+ android:drawableRight="@drawable/ic_action_download"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical" />
+
</LinearLayout>
</ScrollView>
diff --git a/OpenKeychain/src/main/res/layout/view_key_share_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_share_fragment.xml
index 1cd2b9f1b..a8786c461 100644
--- a/OpenKeychain/src/main/res/layout/view_key_share_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_share_fragment.xml
@@ -129,6 +129,29 @@
android:layout_height="1dip"
android:background="?android:attr/listDivider" />
+ <TextView
+ android:id="@+id/view_key_action_upload"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_marginBottom="8dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
+ style="@style/SelectableItem"
+ android:text="@string/key_view_action_upload"
+ android:layout_weight="1"
+ android:drawableRight="@drawable/ic_action_upload"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:editable="false" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
<LinearLayout
android:id="@+id/view_key_action_nfc_help"
android:layout_width="match_parent"
diff --git a/OpenKeychain/src/main/res/layout/view_key_user_id_item.xml b/OpenKeychain/src/main/res/layout/view_key_user_id_item.xml
index 7de2f9c05..157903000 100644
--- a/OpenKeychain/src/main/res/layout/view_key_user_id_item.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_user_id_item.xml
@@ -24,7 +24,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/certified"
- android:src="@drawable/key_certify_ok_self"
android:layout_gravity="center_horizontal" />
</LinearLayout>
@@ -64,9 +63,9 @@
</LinearLayout>
<ImageView
+ android:id="@+id/edit_image"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:id="@+id/edit_image"
android:src="@drawable/ic_action_edit"
android:padding="8dp"
android:layout_gravity="center_horizontal" />
diff --git a/OpenKeychain/src/main/res/menu/key_list.xml b/OpenKeychain/src/main/res/menu/key_list.xml
index e865df182..056dd5986 100644
--- a/OpenKeychain/src/main/res/menu/key_list.xml
+++ b/OpenKeychain/src/main/res/menu/key_list.xml
@@ -10,7 +10,7 @@
app:showAsAction="collapseActionView|ifRoom" />
<item
- android:id="@+id/menu_key_list_import"
+ android:id="@+id/menu_key_list_add"
app:showAsAction="ifRoom|withText"
android:icon="@drawable/ic_action_add_person"
android:title="@string/menu_add_keys" />
@@ -27,6 +27,11 @@
android:title="@string/menu_create_key" />
<item
+ android:id="@+id/menu_key_list_import_existing_key"
+ app:showAsAction="never"
+ android:title="@string/menu_import_existing_key" />
+
+ <item
android:id="@+id/menu_key_list_debug_read"
app:showAsAction="never"
android:title="Debug / DB restore"
diff --git a/OpenKeychain/src/main/res/menu/key_view.xml b/OpenKeychain/src/main/res/menu/key_view.xml
index 64877d725..5a156b5ac 100644
--- a/OpenKeychain/src/main/res/menu/key_view.xml
+++ b/OpenKeychain/src/main/res/menu/key_view.xml
@@ -3,23 +3,6 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
- android:id="@+id/menu_key_keyserver"
- android:icon="@drawable/ic_action_cloud"
- app:showAsAction="always"
- android:title="@string/menu_key_server">
- <menu>
- <item
- android:id="@+id/menu_key_view_update"
- app:showAsAction="never"
- android:title="@string/menu_update_key" />
- <item
- android:id="@+id/menu_key_view_export_keyserver"
- app:showAsAction="never"
- android:title="@string/menu_export_key_to_server" />
- </menu>
- </item>
-
- <item
android:id="@+id/menu_key_view_export_file"
android:icon="@drawable/ic_action_import_export"
app:showAsAction="never"
diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml
index de6962dc9..9d9868457 100644
--- a/OpenKeychain/src/main/res/values-de/strings.xml
+++ b/OpenKeychain/src/main/res/values-de/strings.xml
@@ -247,8 +247,8 @@
<string name="error_only_files_are_supported">Binäre Daten ohne ohne Datei im Dateisystem werden nicht unterstützt.</string>
<string name="error_jelly_bean_needed">Android 4.1 wird benötigt um Androids NFC Beam nutzen zu können!</string>
<string name="error_nfc_needed">NFC steht auf diesem Gerät nicht zur Verfügung!</string>
- <string name="error_keyserver_insufficient_query">zu kurze Schlüsselanfrage</string>
- <string name="error_keyserver_too_many_responses">Die Schlüsselanfrage liefert zu viele Ergebnisse. Bitte verfeinern sie sie Anfrage.</string>
+ <string name="error_query_too_short">zu kurze Schlüsselanfrage</string>
+ <string name="error_too_many_responses">Die Schlüsselanfrage liefert zu viele Ergebnisse. Bitte verfeinern sie sie Anfrage.</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_import_non_pgp_part">
<item quantity="one">Ein Teil der geladenen Datei ist ein gültiges OpenPGP Objekt aber kein OpenPGP Schlüssel</item>
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index 50afd5c57..719ddf414 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -250,10 +250,10 @@
<string name="error_jelly_bean_needed">¡Necesita Android 4.1 para usar la característica NFC Beam (haz NFC) de Android!</string>
<string name="error_nfc_needed">¡NFC no está disponible en tu dispositivo!</string>
<string name="error_nothing_import">¡No se encontraron claves!</string>
- <string name="error_keyserver_insufficient_query">Petición de búsqueda de clave demasiado corta</string>
+ <string name="error_query_too_short">Petición de búsqueda de clave demasiado corta</string>
<string name="error_searching_keys">Error irrecuperable buscando claves en el servidor</string>
- <string name="error_keyserver_too_many_responses">La petición de búsqueda de clave devolvió demasiados candidatos; por favor refine su petición</string>
- <string name="error_import_file_no_content">El Fichero/Portapapeles está vacío</string>
+ <string name="error_too_many_responses">La petición de búsqueda de clave devolvió demasiados candidatos; por favor refine su petición</string>
+ <string name="error_import_no_valid_keys">El Fichero/Portapapeles está vacío</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_import_non_pgp_part">
<item quantity="one">parte del archivo cargado es un objeto OpenPGP válido pero no una clave OpenPGP</item>
@@ -370,7 +370,7 @@
<item quantity="one">Clave%2$s importada con éxito.</item>
<item quantity="other">%1$d claves%2$s importadas con éxito.</item>
</plurals>
- <string name="import_view_log">Ver registro (log)</string>
+ <string name="view_log">Ver registro (log)</string>
<string name="import_error_nothing">No hay nada que importar.</string>
<string name="import_error">¡Error importando claves!</string>
<string name="import_with_warnings">, con advertencias</string>
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index f3627e9eb..0c5c5de67 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -250,10 +250,10 @@
<string name="error_jelly_bean_needed">Il vous faut Android 4.1 pour utiliser la fonction Beam NFC d\'Android !</string>
<string name="error_nfc_needed">La NFC n\'est pas disponible sur votre appareil !</string>
<string name="error_nothing_import">Aucune clef trouvée !</string>
- <string name="error_keyserver_insufficient_query">La requête de recherche de clef est trop courte</string>
+ <string name="error_query_too_short">La requête de recherche de clef est trop courte</string>
<string name="error_searching_keys">Erreur irrécupérable lors de la recherche de clef sur le serveur</string>
- <string name="error_keyserver_too_many_responses">La requête de recherche de clef a retourné trop de candidats. Veuillez raffiner la requête</string>
- <string name="error_import_file_no_content">Le fichier/le presse-papiers est vide</string>
+ <string name="error_too_many_responses">La requête de recherche de clef a retourné trop de candidats. Veuillez raffiner la requête</string>
+ <string name="error_import_no_valid_keys">Le fichier/le presse-papiers est vide</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_import_non_pgp_part">
<item quantity="one">une partie du fichier chargé est un objet OpenPGP valide mais pas une clef OpenPGP</item>
@@ -358,7 +358,7 @@
<item quantity="one">Clef importée avec succès</item>
<item quantity="other">%1$d clefs importées avec succès</item>
</plurals>
- <string name="import_view_log">Consulter le journal</string>
+ <string name="view_log">Consulter le journal</string>
<string name="import_error_nothing">Rien à importer.</string>
<string name="import_error">Erreur lors de l\'importation des clefs !</string>
<string name="import_with_warnings">, avec des avertissements</string>
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index c8ec2614d..074efb78b 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -250,10 +250,10 @@
<string name="error_jelly_bean_needed">Devi avere Android 4.1 per usare Android NFC Beam!</string>
<string name="error_nfc_needed">NFC non disponibile nel tuo dispositivo!</string>
<string name="error_nothing_import">Nessuna chiave trovata!</string>
- <string name="error_keyserver_insufficient_query">Chiave della query di ricerca troppo corta</string>
+ <string name="error_query_too_short">Chiave della query di ricerca troppo corta</string>
<string name="error_searching_keys">Errore irreversibile nella ricerca di chiavi sul server</string>
- <string name="error_keyserver_too_many_responses">Chiave della query di ricerca ha generato troppi candidati; Si prega di perfezionare la ricerca</string>
- <string name="error_import_file_no_content">File/Appunti vuoti</string>
+ <string name="error_too_many_responses">Chiave della query di ricerca ha generato troppi candidati; Si prega di perfezionare la ricerca</string>
+ <string name="error_import_no_valid_keys">File/Appunti vuoti</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_import_non_pgp_part">
<item quantity="one">parte del file caricato e\' un oggetto OpenPGP valido, ma non una chave OpenPGP</item>
@@ -354,7 +354,7 @@
<string name="import_clipboard_button">Ottieni chiave dagli appunti</string>
<string name="import_keybase_button">Ottieni chiave da Keybase.io</string>
<!--Import result toast-->
- <string name="import_view_log">Mostra registro</string>
+ <string name="view_log">Mostra registro</string>
<string name="import_error_nothing">Niente da importare</string>
<string name="import_error">Errore di importazione chiavi!</string>
<string name="import_with_warnings">, con avvisi</string>
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index 13463df25..070ee7f5a 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -246,10 +246,10 @@
<string name="error_jelly_bean_needed">Android NFC Beam機能を使うにはAndroid 4.1 が必要です!</string>
<string name="error_nfc_needed">あなたのデバイスにはNFCが存在しません!</string>
<string name="error_nothing_import">鍵が見当りません!</string>
- <string name="error_keyserver_insufficient_query">鍵検索のクエリが短かすぎます</string>
+ <string name="error_query_too_short">鍵検索のクエリが短かすぎます</string>
<string name="error_searching_keys">サーバでの鍵の検索が回復不可能なエラーになりました</string>
- <string name="error_keyserver_too_many_responses">鍵検索のクエリが沢山の候補を返しました; クエリを精密化してください</string>
- <string name="error_import_file_no_content">ファイル/クリップボードが空です</string>
+ <string name="error_too_many_responses">鍵検索のクエリが沢山の候補を返しました; クエリを精密化してください</string>
+ <string name="error_import_no_valid_keys">ファイル/クリップボードが空です</string>
<string name="error_generic_report_bug">一般エラーが発生しました、この新しいバグの情報をOpenKeychainプロジェクトに送ってください</string>
<plurals name="error_import_non_pgp_part">
<item quantity="other">読み込んだファイルのOpenPGPオブジェクト部分は正しいですが、OpenPGPの鍵ではありません</item>
@@ -358,7 +358,7 @@
<plurals name="import_keys_updated">
<item quantity="other">%1$d の鍵%2$sのアップデートに成功。</item>
</plurals>
- <string name="import_view_log">ログを見る</string>
+ <string name="view_log">ログを見る</string>
<string name="import_error_nothing">インポートするものがありません。</string>
<string name="import_error">鍵のインポートのエラー!</string>
<string name="import_with_warnings">、とワーニング</string>
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index 539a431b5..1e697c8db 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -254,10 +254,10 @@
<string name="error_jelly_bean_needed">Для использования NFC Beam требуется Android 4.1+ !</string>
<string name="error_nfc_needed">Ваше устройство не поддерживает NFC!</string>
<string name="error_nothing_import">Ключи не найдены!</string>
- <string name="error_keyserver_insufficient_query">Запрос слишком короткий</string>
+ <string name="error_query_too_short">Запрос слишком короткий</string>
<string name="error_searching_keys">Ошибка поиска ключей на сервере</string>
- <string name="error_keyserver_too_many_responses">Поиск ключа вернул слишком много вариантов; Пожалуйста, уточните запрос</string>
- <string name="error_import_file_no_content">Файл/Буфер пуст</string>
+ <string name="error_too_many_responses">Поиск ключа вернул слишком много вариантов; Пожалуйста, уточните запрос</string>
+ <string name="error_import_no_valid_keys">Файл/Буфер пуст</string>
<string name="error_generic_report_bug">Выявлена ошибка. Пожалуйста, сообщите о ней разработчику.</string>
<plurals name="error_import_non_pgp_part">
<item quantity="one">часть загруженного файла содержит данные OpenPGP, но это не ключ</item>
@@ -371,7 +371,7 @@
<item quantity="few">и обновлено %1$d ключей%2$s.</item>
<item quantity="other">и обновлено %1$d ключей%2$s.</item>
</plurals>
- <string name="import_view_log">Смотреть журнал</string>
+ <string name="view_log">Смотреть журнал</string>
<string name="import_error_nothing">Нет данных для импорта.</string>
<string name="import_error">Ошибка импорта ключей!</string>
<string name="import_with_warnings">, с предупреждениями</string>
diff --git a/OpenKeychain/src/main/res/values-sl/strings.xml b/OpenKeychain/src/main/res/values-sl/strings.xml
index 61fe6ed86..b9a0c4cb9 100644
--- a/OpenKeychain/src/main/res/values-sl/strings.xml
+++ b/OpenKeychain/src/main/res/values-sl/strings.xml
@@ -254,9 +254,9 @@
<string name="error_only_files_are_supported">Neposredni binarni podatki brez dejanske datoteke v datotečnem sistemu niso podprti.</string>
<string name="error_jelly_bean_needed">Za uporabo storitve NFC Beam potrebujete najmanj Android 4.1!</string>
<string name="error_nfc_needed">NFC ni na voljo na vaši napravi!</string>
- <string name="error_keyserver_insufficient_query">Iskalni pojem je prekratek</string>
+ <string name="error_query_too_short">Iskalni pojem je prekratek</string>
<string name="error_searching_keys">Nepremostljiva napaka pri iskanju ključev na strežniku</string>
- <string name="error_keyserver_too_many_responses">Iskanje ključev je vrnilo preveč zadetkov; prosimo redefinirajte iskalni pojem</string>
+ <string name="error_too_many_responses">Iskanje ključev je vrnilo preveč zadetkov; prosimo redefinirajte iskalni pojem</string>
<string name="error_generic_report_bug">Pripetila se je splošna napaka, prosimo ustvarite poročilo o \'hrošču\'.</string>
<plurals name="error_import_non_pgp_part">
<item quantity="one">Del naložene datoteke je veljavnen objekt OpenPGP a ni ključ.</item>
diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml
index 6f5cc7cf1..4e267e431 100644
--- a/OpenKeychain/src/main/res/values-uk/strings.xml
+++ b/OpenKeychain/src/main/res/values-uk/strings.xml
@@ -252,9 +252,9 @@
<string name="error_jelly_bean_needed">Вам потрібний Android 4.1 для використання функції Androids NFC промінь!</string>
<string name="error_nfc_needed">NFC недоступний на вашому пристрої!</string>
<string name="error_nothing_import">Ключ не знайдено!</string>
- <string name="error_keyserver_insufficient_query">Запит пошуку ключа надто короткий</string>
+ <string name="error_query_too_short">Запит пошуку ключа надто короткий</string>
<string name="error_searching_keys">Невиправна помилка пошуку ключів в сервері</string>
- <string name="error_keyserver_too_many_responses">Запит пошуку ключа видав надто багато варіантів. Уточніть пошуковий запит</string>
+ <string name="error_too_many_responses">Запит пошуку ключа видав надто багато варіантів. Уточніть пошуковий запит</string>
<string name="error_generic_report_bug">Трапилася загальна помилка, будь ласка, створіть новий звіт про помилку для OpenKeychain.</string>
<plurals name="error_import_non_pgp_part">
<item quantity="one">частина завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
@@ -352,7 +352,7 @@
<string name="import_clipboard_button">Отримати ключ з буфера обміну</string>
<string name="import_keybase_button">Отримати ключ із Keybase.io</string>
<!--Import result toast-->
- <string name="import_view_log">Переглянути журнал</string>
+ <string name="view_log">Переглянути журнал</string>
<string name="import_error_nothing">Нема що імпортувати.</string>
<string name="import_error">Помилка імпорту ключів!</string>
<!--Intent labels-->
diff --git a/OpenKeychain/src/main/res/values/colors.xml b/OpenKeychain/src/main/res/values/colors.xml
index c0042d215..a21f949d1 100644
--- a/OpenKeychain/src/main/res/values/colors.xml
+++ b/OpenKeychain/src/main/res/values/colors.xml
@@ -5,12 +5,19 @@
<color name="emphasis_dark">#9933cc</color>
<color name="bg_gray">#cecbce</color>
<color name="tertiary_text_light">#808080</color>
+ <color name="alert">#ffdd3333</color>
<color name="holo_gray_light">#33999999</color>
<color name="holo_gray_bright">#33CCCCCC</color>
- <color name="result_red">#ffff4444</color>
- <color name="result_orange">#ffffbb33</color>
- <color name="result_green">#ff99cc00</color>
- <color name="result_purple">#aa66cc</color>
+ <!-- http://developer.android.com/design/style/color.html -->
+ <color name="android_red_light">#ffff4444</color>
+ <color name="android_red_dark">#ffCC0000</color>
+ <color name="android_orange_light">#ffffbb33</color>
+ <color name="android_orange_dark">#ffFF8800</color>
+ <color name="android_green_light">#ff99cc00</color>
+ <color name="android_green_dark">#ff669900</color>
+ <color name="android_purple_light">#ffaa66cc</color>
+ <color name="android_purple_dark">#ff9933CC</color>
+
</resources>
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 87b2a83be..432c8bfc9 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -2,12 +2,12 @@
<resources>
<!-- title -->
- <string name="title_select_recipients">Select Public Key</string>
- <string name="title_select_secret_key">Select Secret Key</string>
+ <string name="title_select_recipients">Select Keys</string>
+ <string name="title_select_secret_key">Select Your Key</string>
<string name="title_encrypt">Encrypt</string>
<string name="title_decrypt">Decrypt</string>
<string name="title_authentication">Passphrase</string>
- <string name="title_create_key">Create Key</string>
+ <string name="title_create_key">Create My Key</string>
<string name="title_edit_key">Edit Key</string>
<string name="title_preferences">Preferences</string>
<string name="title_api_registered_apps">Apps</string>
@@ -71,18 +71,17 @@
<string name="btn_encryption_advanced_settings_hide">Hide advanced settings</string>
<string name="btn_share_encrypted_signed">Share encrypted/signed message…</string>
<string name="btn_view_cert_key">View certification key</string>
+ <string name="btn_create_key">Create key</string>
<!-- menu -->
<string name="menu_preferences">Settings</string>
<string name="menu_help">Help</string>
<string name="menu_export_key">Export to file</string>
<string name="menu_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_create_key">Create my key</string>
+ <string name="menu_import_existing_key">Import existing key</string>
<string name="menu_search">Search</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_title_fingerprint">Share fingerprint…</string>
<string name="menu_share_title">Share whole key…</string>
@@ -106,7 +105,7 @@
<string name="label_file">File</string>
<string name="label_no_passphrase">No Passphrase</string>
<string name="label_passphrase">Passphrase</string>
- <string name="label_passphrase_again">Again</string>
+ <string name="label_passphrase_again">Repeat Passphrase</string>
<string name="label_algorithm">Algorithm</string>
<string name="label_ascii_armor">ASCII Armor</string>
<string name="label_conceal_pgp_application">Let others know that you\'re using OpenKeychain</string>
@@ -216,7 +215,7 @@
<string name="ask_save_changed_key">You have made changes to the keyring, would you like to save it?</string>
<string name="ask_empty_id_ok">You have added an empty identity, are you sure you want to continue?</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="also_export_secret_keys">Also export secret keys?</string>
+ <string name="also_export_secret_keys">Also export secret keys</string>
<string name="key_exported">Successfully exported 1 key.</string>
<string name="keys_exported">Successfully exported %d keys.</string>
@@ -269,10 +268,12 @@
<string name="error_jelly_bean_needed">You need Android 4.1 to use Android\'s NFC Beam feature!</string>
<string name="error_nfc_needed">NFC is not available on your device!</string>
<string name="error_nothing_import">No keys found!</string>
- <string name="error_keyserver_insufficient_query">Key search query too short</string>
- <string name="error_searching_keys">Unrecoverable error searching for keys at server</string>
- <string name="error_keyserver_too_many_responses">Key search query returned too many candidates; Please refine query</string>
- <string name="error_import_file_no_content">File/Clipboard is empty</string>
+ <string name="error_query_too_short">Search query too short. Please refine your query!</string>
+ <string name="error_searching_keys">An error occurred when searching for keys.</string>
+ <string name="error_too_many_responses">Key search query returned too many candidates. Please refine your query!</string>
+ <string name="error_too_short_or_too_many_responses">Either no keys or too many have been found. Please improve your query!</string>
+
+ <string name="error_import_no_valid_keys">No valid keys found in File/Clipboard!</string>
<string name="error_generic_report_bug">A generic error occurred, please create a new bug report for OpenKeychain.</string>
<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>
@@ -296,11 +297,26 @@
<string name="progress_saving">saving…</string>
<string name="progress_importing">importing…</string>
<string name="progress_exporting">exporting…</string>
+ <string name="progress_uploading">uploading…</string>
<string name="progress_building_key">building key…</string>
<string name="progress_certifying_master_key">certifying master key…</string>
<string name="progress_building_master_key">building master ring…</string>
<string name="progress_adding_sub_keys">adding sub keys…</string>
<string name="progress_saving_key_ring">saving key…</string>
+ <string name="progress_generating_rsa">generating new RSA key…</string>
+ <string name="progress_generating_dsa">generating new DSA key…</string>
+ <string name="progress_generating_elgamal">generating new ElGamal key…</string>
+
+ <string name="progress_modify">modifying keyring…</string>
+
+ <string name="progress_modify_unlock">unlocking keyring…</string>
+ <string name="progress_modify_adduid">adding user ids…</string>
+ <string name="progress_modify_revokeuid">revoking user ids…</string>
+ <string name="progress_modify_primaryuid">changing primary user id…</string>
+ <string name="progress_modify_subkeychange">modifying subkeys…</string>
+ <string name="progress_modify_subkeyrevoke">revoking subkeys…</string>
+ <string name="progress_modify_subkeyadd">adding subkeys…</string>
+ <string name="progress_modify_passphrase">changing passphrase…</string>
<plurals name="progress_exporting_key">
<item quantity="one">exporting key…</item>
@@ -322,6 +338,7 @@
<string name="progress_processing_signature">processing signature…</string>
<string name="progress_verifying_signature">verifying signature…</string>
<string name="progress_signing">signing…</string>
+ <string name="progress_certifying">certifying…</string>
<string name="progress_reading_data">reading data…</string>
<string name="progress_finding_key">finding key…</string>
<string name="progress_decompressing_data">decompressing data…</string>
@@ -330,7 +347,6 @@
<!-- action strings -->
<string name="hint_public_keys">Name/Email/Key ID…</string>
- <string name="hint_secret_keys">Search Secret Keys</string>
<string name="action_share_key_with">Share Key with…</string>
<string name="hint_keybase_search">Name/Keybase.io username…</string>
@@ -391,8 +407,8 @@
<item quantity="other">Successfully imported %1$d keys</item>
</plurals>
<plurals name="import_keys_added_and_updated_2">
- <item quantity="one"> and updated key%2$s.</item>
- <item quantity="other"> and updated %1$d keys%2$s.</item>
+ <item quantity="one">and updated key%2$s.</item>
+ <item quantity="other">and updated %1$d keys%2$s.</item>
</plurals>
<plurals name="import_keys_added">
<item quantity="one">Successfully imported key%2$s.</item>
@@ -402,7 +418,7 @@
<item quantity="one">Successfully updated key%2$s.</item>
<item quantity="other">Successfully updated %1$d keys%2$s.</item>
</plurals>
- <string name="import_view_log">View Log</string>
+ <string name="view_log">View Log</string>
<string name="import_error_nothing">Nothing to import.</string>
<string name="import_error">Error importing keys!</string>
<string name="import_with_warnings">, with warnings</string>
@@ -431,7 +447,7 @@
<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 app.</string>
- <string name="api_create_account_text">The app requests the creation of a new account. Please select an existing private key or create a new one.\nApps are restricted to the usage of keys you select here!</string>
+ <string name="api_create_account_text">The app requests the creation of a new account. Please select one of your existing keys or create a new one.\nApps are restricted to the usage of keys you select here!</string>
<string name="api_register_text">The displayed app wants to encrypt/decrypt messages and sign them in your name.\nAllow access?\n\nWARNING: If you do not know why this screen appeared, disallow access! You can revoke access later using the \'Apps\' screen.</string>
<string name="api_register_allow">Allow access</string>
<string name="api_register_disallow">Disallow access</string>
@@ -458,14 +474,16 @@
<string name="key_list_empty_text2">You can start by</string>
<string name="key_list_empty_text3">or</string>
<string name="key_list_empty_button_create">creating your own key</string>
- <string name="key_list_empty_button_import">importing keys.</string>
+ <string name="key_list_empty_button_import">importing an existing key.</string>
<!-- Key view -->
<string name="key_view_action_edit">Edit key</string>
<string name="key_view_action_encrypt">Encrypt with this key</string>
<string name="key_view_action_certify">Certify identities</string>
+ <string name="key_view_action_update">Update from keyserver</string>
<string name="key_view_action_share_with">Share with…</string>
<string name="key_view_action_share_nfc">Share over NFC by holding the devices back to back</string>
+ <string name="key_view_action_upload">Upload to key server</string>
<string name="key_view_tab_main">Main Info</string>
<string name="key_view_tab_share">Share</string>
<string name="key_view_tab_keys">Subkeys</string>
@@ -486,6 +504,19 @@
<item>Revoke Subkey</item>
</string-array>
+ <!-- Create key -->
+ <string name="create_key_upload">Upload key to keyserver</string>
+ <string name="create_key_empty">This field is required</string>
+ <string name="create_key_passphrases_not_equal">Passphrases do not match</string>
+ <string name="create_key_final_text">You entered the following identity:</string>
+ <string name="create_key_final_robot_text">Creating a key may take a while, have a cup of coffee in the meantime…\n(3 subkeys, RSA, 4096 bit)</string>
+ <string name="create_key_text">Enter your full name, email address, and choose a passhrase.</string>
+ <string name="create_key_hint_full_name">Full Name, e.g. Max Mustermann</string>
+
+ <!-- View key -->
+ <string name="view_key_revoked">This key has been revoked!</string>
+ <string name="view_key_expired">This key is expired!</string>
+
<!-- Navigation Drawer -->
<string name="nav_keys">Keys</string>
<string name="nav_encrypt">Sign and Encrypt</string>
@@ -496,9 +527,6 @@
<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>
<!-- hints -->
<string name="encrypt_content_edit_text_hint">Write message here to encrypt and/or sign…</string>
@@ -569,6 +597,7 @@
<string name="msg_ip_uid_processing">Processing user id %s</string>
<string name="msg_ip_uid_revoked">User id is revoked</string>
<string name="msg_is_bad_type_public">Tried to import public keyring as secret. This is a bug, please file a report!</string>
+ <string name="msg_is_bad_type_uncanon">Tried to import a keyring without canonicalization. This is a bug, please file a report!</string>
<!-- Import Secret log entries -->
<string name="msg_is">Importing secret key %s</string>
@@ -673,6 +702,7 @@
<string name="msg_mf_uid_add">Adding user id %s</string>
<string name="msg_mf_uid_primary">Changing primary uid to %s</string>
<string name="msg_mf_uid_revoke">Revoking user id %s</string>
+ <string name="msg_mf_uid_error_empty">User ID must not be empty!</string>
<string name="msg_mf_unlock_error">Error unlocking keyring!</string>
<string name="msg_mf_unlock">Unlocking keyring</string>
@@ -684,6 +714,7 @@
<string name="passp_cache_notif_pwd">Password</string>
<!-- unsorted -->
+ <string name="internal_error">Internal error!</string>
<string name="section_certifier_id">Certifier</string>
<string name="section_cert">Certificate Details</string>
<string name="label_user_id">Identity</string>
@@ -697,7 +728,7 @@
<string name="error_key_processing">Error processing key!</string>
<string name="no_subkey">subkey unavailable</string>
<string name="key_stripped">stripped</string>
- <string name="secret_cannot_multiple">Secret keys can only be deleted individually!</string>
+ <string name="secret_cannot_multiple">Your own keys can only be deleted individually!</string>
<string name="title_view_cert">View Certificate Details</string>
<string name="unknown_algorithm">unknown</string>
<string name="can_sign_not">cannot sign</string>
@@ -708,8 +739,8 @@
<!-- First Time -->
<string name="first_time_text1">Take back your privacy with OpenKeychain!</string>
- <string name="first_time_create_key">Create Key</string>
- <string name="first_time_import_key">Import Key</string>
+ <string name="first_time_create_key">Create my key</string>
+ <string name="first_time_import_key">Import existing key</string>
<string name="first_time_skip">Skip Setup</string>
</resources>