diff options
author | Thialfihar <thialfihar@gmail.com> | 2010-05-18 15:23:25 +0000 |
---|---|---|
committer | Thialfihar <thialfihar@gmail.com> | 2010-05-18 15:23:25 +0000 |
commit | ed2cb1e525778d62949958bbf108687c571e4ebe (patch) | |
tree | e27fd3f422580b22b2a7f34bb0d4d53edccaa680 | |
parent | 42f1720bb32b5404ae9b78c0b042b143b6f507af (diff) | |
parent | 5b5e15c88663acfc282d42ff51cdceff1d9d4084 (diff) | |
download | open-keychain-ed2cb1e525778d62949958bbf108687c571e4ebe.tar.gz open-keychain-ed2cb1e525778d62949958bbf108687c571e4ebe.tar.bz2 open-keychain-ed2cb1e525778d62949958bbf108687c571e4ebe.zip |
overdue merge of 0.9.x into trunk
-rw-r--r-- | AndroidManifest.xml | 109 | ||||
-rw-r--r-- | res/anim/push_left_in.xml | 20 | ||||
-rw-r--r-- | res/anim/push_left_out.xml | 20 | ||||
-rw-r--r-- | res/anim/push_right_in.xml | 20 | ||||
-rw-r--r-- | res/anim/push_right_out.xml | 20 | ||||
-rw-r--r-- | res/drawable-hdpi-finger-v4/btn_circle_disable.png (renamed from res/drawable-hdpi-finger/btn_circle_disable.png) | bin | 2631 -> 2631 bytes | |||
-rw-r--r-- | res/drawable-hdpi-finger-v4/btn_circle_disable_focused.png (renamed from res/drawable-hdpi-finger/btn_circle_disable_focused.png) | bin | 3001 -> 3001 bytes | |||
-rw-r--r-- | res/drawable-hdpi-finger-v4/btn_circle_normal.png (renamed from res/drawable-hdpi-finger/btn_circle_normal.png) | bin | 1974 -> 1974 bytes | |||
-rw-r--r-- | res/drawable-hdpi-finger-v4/btn_circle_pressed.png (renamed from res/drawable-hdpi-finger/btn_circle_pressed.png) | bin | 2624 -> 2624 bytes | |||
-rw-r--r-- | res/drawable-hdpi-finger-v4/btn_circle_selected.png (renamed from res/drawable-hdpi-finger/btn_circle_selected.png) | bin | 2554 -> 2554 bytes | |||
-rw-r--r-- | res/drawable-hdpi-finger-v4/ic_btn_round_minus.png (renamed from res/drawable-hdpi-finger/ic_btn_round_minus.png) | bin | 536 -> 536 bytes | |||
-rw-r--r-- | res/drawable-hdpi-finger-v4/ic_btn_round_plus.png (renamed from res/drawable-hdpi-finger/ic_btn_round_plus.png) | bin | 1316 -> 1316 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/encrypted.png (renamed from res/drawable-hdpi/encrypted.png) | bin | 3561 -> 3561 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/encrypted_large.png (renamed from res/drawable-hdpi/encrypted_large.png) | bin | 5244 -> 5244 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/encrypted_small.png (renamed from res/drawable-hdpi/encrypted_small.png) | bin | 2187 -> 2187 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/ic_next.png | bin | 0 -> 1722 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/ic_previous.png | bin | 0 -> 1712 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/icon.png (renamed from res/drawable-hdpi/icon.png) | bin | 5563 -> 5563 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/key.png (renamed from res/drawable-hdpi/key.png) | bin | 3675 -> 3675 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/key_large.png (renamed from res/drawable-hdpi/key_large.png) | bin | 5550 -> 5550 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/key_small.png (renamed from res/drawable-hdpi/key_small.png) | bin | 2088 -> 2088 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/overlay_error.png (renamed from res/drawable-hdpi/overlay_error.png) | bin | 1986 -> 1986 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/overlay_ok.png (renamed from res/drawable-hdpi/overlay_ok.png) | bin | 1702 -> 1702 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/signed.png (renamed from res/drawable-hdpi/signed.png) | bin | 3858 -> 3858 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/signed_large.png (renamed from res/drawable-hdpi/signed_large.png) | bin | 5928 -> 5928 bytes | |||
-rw-r--r-- | res/drawable-hdpi-v4/signed_small.png (renamed from res/drawable-hdpi/signed_small.png) | bin | 2219 -> 2219 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/encrypted.png (renamed from res/drawable-ldpi/encrypted.png) | bin | 1513 -> 1513 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/encrypted_large.png (renamed from res/drawable-ldpi/encrypted_large.png) | bin | 2486 -> 2486 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/encrypted_small.png (renamed from res/drawable-ldpi/encrypted_small.png) | bin | 1176 -> 1176 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/ic_next.png | bin | 0 -> 916 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/ic_previous.png | bin | 0 -> 922 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/icon.png (renamed from res/drawable-ldpi/icon.png) | bin | 1948 -> 1948 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/key.png (renamed from res/drawable-ldpi/key.png) | bin | 1484 -> 1484 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/key_large.png (renamed from res/drawable-ldpi/key_large.png) | bin | 2462 -> 2462 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/key_small.png (renamed from res/drawable-ldpi/key_small.png) | bin | 1074 -> 1074 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/overlay_error.png (renamed from res/drawable-ldpi/overlay_error.png) | bin | 1192 -> 1192 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/overlay_ok.png (renamed from res/drawable-ldpi/overlay_ok.png) | bin | 1038 -> 1038 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/signed.png (renamed from res/drawable-ldpi/signed.png) | bin | 1576 -> 1576 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/signed_large.png (renamed from res/drawable-ldpi/signed_large.png) | bin | 2611 -> 2611 bytes | |||
-rw-r--r-- | res/drawable-ldpi-v4/signed_small.png (renamed from res/drawable-ldpi/signed_small.png) | bin | 1149 -> 1149 bytes | |||
-rw-r--r-- | res/drawable-mdpi-finger-v4/btn_circle_disable.png (renamed from res/drawable-mdpi-finger/btn_circle_disable.png) | bin | 938 -> 938 bytes | |||
-rw-r--r-- | res/drawable-mdpi-finger-v4/btn_circle_disable_focused.png (renamed from res/drawable-mdpi-finger/btn_circle_disable_focused.png) | bin | 1436 -> 1436 bytes | |||
-rw-r--r-- | res/drawable-mdpi-finger-v4/btn_circle_normal.png (renamed from res/drawable-mdpi-finger/btn_circle_normal.png) | bin | 1249 -> 1249 bytes | |||
-rw-r--r-- | res/drawable-mdpi-finger-v4/btn_circle_pressed.png (renamed from res/drawable-mdpi-finger/btn_circle_pressed.png) | bin | 1613 -> 1613 bytes | |||
-rw-r--r-- | res/drawable-mdpi-finger-v4/btn_circle_selected.png (renamed from res/drawable-mdpi-finger/btn_circle_selected.png) | bin | 1645 -> 1645 bytes | |||
-rw-r--r-- | res/drawable-mdpi-finger-v4/ic_btn_round_minus.png (renamed from res/drawable-mdpi-finger/ic_btn_round_minus.png) | bin | 288 -> 288 bytes | |||
-rw-r--r-- | res/drawable-mdpi-finger-v4/ic_btn_round_plus.png (renamed from res/drawable-mdpi-finger/ic_btn_round_plus.png) | bin | 526 -> 526 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/encrypted.png (renamed from res/drawable-mdpi/encrypted.png) | bin | 2486 -> 2486 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/encrypted_large.png (renamed from res/drawable-mdpi/encrypted_large.png) | bin | 3561 -> 3561 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/encrypted_small.png (renamed from res/drawable-mdpi/encrypted_small.png) | bin | 1513 -> 1513 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/ic_next.png | bin | 0 -> 1360 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/ic_previous.png | bin | 0 -> 1352 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/icon.png (renamed from res/drawable-mdpi/icon.png) | bin | 2947 -> 2947 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/key.png (renamed from res/drawable-mdpi/key.png) | bin | 2462 -> 2462 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/key_large.png (renamed from res/drawable-mdpi/key_large.png) | bin | 3675 -> 3675 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/key_small.png (renamed from res/drawable-mdpi/key_small.png) | bin | 1484 -> 1484 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/overlay_error.png (renamed from res/drawable-mdpi/overlay_error.png) | bin | 1539 -> 1539 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/overlay_ok.png (renamed from res/drawable-mdpi/overlay_ok.png) | bin | 1305 -> 1305 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/signed.png (renamed from res/drawable-mdpi/signed.png) | bin | 2611 -> 2611 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/signed_large.png (renamed from res/drawable-mdpi/signed_large.png) | bin | 3858 -> 3858 bytes | |||
-rw-r--r-- | res/drawable-mdpi-v4/signed_small.png (renamed from res/drawable-mdpi/signed_small.png) | bin | 1576 -> 1576 bytes | |||
-rw-r--r-- | res/drawable/btn_circle_disable.png | bin | 0 -> 938 bytes | |||
-rw-r--r-- | res/drawable/btn_circle_disable_focused.png | bin | 0 -> 1436 bytes | |||
-rw-r--r-- | res/drawable/btn_circle_normal.png | bin | 0 -> 1249 bytes | |||
-rw-r--r-- | res/drawable/btn_circle_pressed.png | bin | 0 -> 1613 bytes | |||
-rw-r--r-- | res/drawable/btn_circle_selected.png | bin | 0 -> 1645 bytes | |||
-rw-r--r-- | res/drawable/encrypted.png | bin | 0 -> 2486 bytes | |||
-rw-r--r-- | res/drawable/encrypted_large.png | bin | 0 -> 3561 bytes | |||
-rw-r--r-- | res/drawable/encrypted_small.png | bin | 0 -> 1513 bytes | |||
-rw-r--r-- | res/drawable/ic_btn_round_minus.png | bin | 0 -> 288 bytes | |||
-rw-r--r-- | res/drawable/ic_btn_round_plus.png | bin | 0 -> 526 bytes | |||
-rw-r--r-- | res/drawable/ic_launcher_folder.png | bin | 0 -> 2235 bytes | |||
-rw-r--r-- | res/drawable/ic_launcher_folder_small.png | bin | 0 -> 1522 bytes | |||
-rw-r--r-- | res/drawable/ic_next.png | bin | 0 -> 1360 bytes | |||
-rw-r--r-- | res/drawable/ic_previous.png | bin | 0 -> 1352 bytes | |||
-rw-r--r-- | res/drawable/icon.png | bin | 0 -> 2947 bytes | |||
-rw-r--r-- | res/drawable/key.png | bin | 0 -> 2462 bytes | |||
-rw-r--r-- | res/drawable/key_large.png | bin | 0 -> 3675 bytes | |||
-rw-r--r-- | res/drawable/key_small.png | bin | 0 -> 1484 bytes | |||
-rw-r--r-- | res/drawable/overlay_error.png | bin | 0 -> 1539 bytes | |||
-rw-r--r-- | res/drawable/overlay_ok.png | bin | 0 -> 1305 bytes | |||
-rw-r--r-- | res/drawable/signed.png | bin | 0 -> 2611 bytes | |||
-rw-r--r-- | res/drawable/signed_large.png | bin | 0 -> 3858 bytes | |||
-rw-r--r-- | res/drawable/signed_small.png | bin | 0 -> 1576 bytes | |||
-rw-r--r-- | res/layout/account_item.xml | 14 | ||||
-rw-r--r-- | res/layout/create_key.xml | 14 | ||||
-rw-r--r-- | res/layout/decrypt.xml | 214 | ||||
-rw-r--r-- | res/layout/decrypt_message.xml | 97 | ||||
-rw-r--r-- | res/layout/edit_key.xml | 29 | ||||
-rw-r--r-- | res/layout/edit_key_key_item.xml | 216 | ||||
-rw-r--r-- | res/layout/edit_key_section.xml | 2 | ||||
-rw-r--r-- | res/layout/edit_key_user_id_item.xml | 167 | ||||
-rw-r--r-- | res/layout/encrypt.xml | 382 | ||||
-rw-r--r-- | res/layout/encrypt_message.xml | 95 | ||||
-rw-r--r-- | res/layout/file_dialog.xml | 37 | ||||
-rw-r--r-- | res/layout/info.xml | 15 | ||||
-rw-r--r-- | res/layout/key_list.xml | 28 | ||||
-rw-r--r-- | res/layout/key_list_child_item_master_key.xml | 88 | ||||
-rw-r--r-- | res/layout/key_list_child_item_sub_key.xml | 76 | ||||
-rw-r--r-- | res/layout/key_list_child_item_user_id.xml | 14 | ||||
-rw-r--r-- | res/layout/key_list_group_item.xml | 55 | ||||
-rw-r--r-- | res/layout/mailbox_message_item.xml | 58 | ||||
-rw-r--r-- | res/layout/main.xml | 92 | ||||
-rw-r--r-- | res/layout/pass_phrase.xml | 22 | ||||
-rw-r--r-- | res/layout/preferences.xml | 197 | ||||
-rw-r--r-- | res/layout/select_public_key.xml | 57 | ||||
-rw-r--r-- | res/layout/select_public_key_item.xml | 136 | ||||
-rw-r--r-- | res/layout/select_secret_key.xml | 9 | ||||
-rw-r--r-- | res/layout/select_secret_key_item.xml | 111 | ||||
-rw-r--r-- | res/values-de/strings.xml | 230 | ||||
-rw-r--r-- | res/values-ko/strings.xml | 230 | ||||
-rw-r--r-- | res/values-ru/strings.xml | 230 | ||||
-rw-r--r-- | res/values/strings.xml | 205 | ||||
-rw-r--r-- | src/org/openintents/intents/FileManager.java | 78 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/Apg.java | 930 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java | 98 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/BaseActivity.java | 467 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/CachedPassPhrase.java | 39 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/Constants.java | 35 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/DecryptActivity.java | 647 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/DecryptMessageActivity.java | 343 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/EditKeyActivity.java | 255 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/EncryptActivity.java | 810 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/EncryptMessageActivity.java | 428 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/FileDialog.java | 119 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/Id.java | 129 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/MailListActivity.java | 42 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/MainActivity.java | 295 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/PositionAwareInputStream.java | 67 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/PreferencesActivity.java | 222 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/Primes.java | 185 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/ProgressDialogUpdater.java | 1 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/PublicKeyListActivity.java | 459 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/SecretKeyListActivity.java | 535 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/SelectPublicKeyListActivity.java | 168 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/SelectPublicKeyListAdapter.java | 186 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/SelectSecretKeyListActivity.java | 29 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/provider/DataProvider.java | 9 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/ui/widget/KeyEditor.java | 94 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/ui/widget/SectionView.java | 76 | ||||
-rw-r--r-- | src/org/thialfihar/android/apg/ui/widget/UserIdEditor.java | 7 |
141 files changed, 7001 insertions, 3061 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5a41f262d..03a653c66 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -14,75 +14,104 @@ limitations under the License. --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="org.thialfihar.android.apg" - android:versionCode="3" android:versionName="0.8.0"> - <application android:icon="@drawable/icon" android:label="@string/app_name"> - <activity android:name=".MainActivity" - android:label="@string/app_name" - android:configChanges="keyboardHidden|orientation|keyboard"> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="org.thialfihar.android.apg" + android:versionName="0.9.5" android:versionCode="10"> + + <application + android:icon="@drawable/icon" + android:label="@string/app_name"> + + <activity + android:name=".MainActivity" + android:label="@string/app_name" + android:configChanges="keyboardHidden|orientation|keyboard"> + <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> - </activity> - <activity android:name=".PublicKeyListActivity" - android:label="@string/title_managePublicKeys" - android:configChanges="keyboardHidden|orientation|keyboard"> </activity> - <activity android:name=".SecretKeyListActivity" - android:label="@string/title_manageSecretKeys" - android:configChanges="keyboardHidden|orientation|keyboard"> - </activity> + <activity + android:name=".PublicKeyListActivity" + android:label="@string/title_managePublicKeys" + android:configChanges="keyboardHidden|orientation|keyboard" /> - <activity android:name=".EditKeyActivity" - android:label="@string/title_editKey" - android:configChanges="keyboardHidden|orientation|keyboard"> - </activity> + <activity + android:name=".SecretKeyListActivity" + android:label="@string/title_manageSecretKeys" + android:configChanges="keyboardHidden|orientation|keyboard"/> - <activity android:name=".SelectPublicKeyListActivity" - android:label="@string/title_selectRecipients" - android:configChanges="keyboardHidden|orientation|keyboard"> - </activity> + <activity + android:name=".EditKeyActivity" + android:label="@string/title_editKey" + android:configChanges="keyboardHidden|orientation|keyboard"/> - <activity android:name=".SelectSecretKeyListActivity" - android:label="@string/title_selectSignature" - android:configChanges="keyboardHidden|orientation|keyboard"> - </activity> + <activity + android:name=".SelectPublicKeyListActivity" + android:label="@string/title_selectRecipients" + android:configChanges="keyboardHidden|orientation|keyboard"/> + + <activity + android:name=".SelectSecretKeyListActivity" + android:label="@string/title_selectSignature" + android:configChanges="keyboardHidden|orientation|keyboard"/> + + <activity + android:name=".EncryptActivity" + android:label="@string/title_encrypt" + android:configChanges="keyboardHidden|orientation|keyboard"> - <activity android:name=".EncryptMessageActivity" - android:label="@string/title_encryptMessage" - android:configChanges="keyboardHidden|orientation|keyboard"> <intent-filter> <action android:name="org.thialfihar.android.apg.intent.ENCRYPT" /> + <action android:name="org.thialfihar.android.apg.intent.ENCRYPT_FILE" /> </intent-filter> + </activity> - <activity android:name=".DecryptMessageActivity" - android:label="@string/title_decryptMessage" - android:configChanges="keyboardHidden|orientation|keyboard"> + <activity + android:name=".DecryptActivity" + android:label="@string/title_decrypt" + android:configChanges="keyboardHidden|orientation|keyboard"> + <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/*"/> </intent-filter> + + <intent-filter> + <action android:name="android.intent.action.SEND" /> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="text/*"/> + </intent-filter> + <intent-filter> <action android:name="org.thialfihar.android.apg.intent.DECRYPT" /> + <action android:name="org.thialfihar.android.apg.intent.DECRYPT_FILE" /> </intent-filter> - </activity> - <activity android:name=".MailListActivity" - android:label="@string/title_mailInbox" - android:configChanges="keyboardHidden|orientation|keyboard"> </activity> - <provider android:name="org.thialfihar.android.apg.provider.DataProvider" - android:authorities="org.thialfihar.android.apg.provider" /> + <activity + android:name=".MailListActivity" + android:label="@string/title_mailInbox" + android:configChanges="keyboardHidden|orientation|keyboard"/> + + <activity + android:name=".PreferencesActivity" + android:label="@string/title_preferences" + android:configChanges="keyboardHidden|orientation|keyboard"/> + + <provider + android:name="org.thialfihar.android.apg.provider.DataProvider" + android:authorities="org.thialfihar.android.apg.provider" /> </application> - <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="5" /> + <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="5" /> <uses-permission android:name="com.google.android.providers.gmail.permission.READ_GMAIL" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> diff --git a/res/anim/push_left_in.xml b/res/anim/push_left_in.xml new file mode 100644 index 000000000..b7d2d0da0 --- /dev/null +++ b/res/anim/push_left_in.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="500"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0" android:duration="500" />
+</set>
diff --git a/res/anim/push_left_out.xml b/res/anim/push_left_out.xml new file mode 100644 index 000000000..6bdc0ce47 --- /dev/null +++ b/res/anim/push_left_out.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="500"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0" android:duration="500" />
+</set>
\ No newline at end of file diff --git a/res/anim/push_right_in.xml b/res/anim/push_right_in.xml new file mode 100644 index 000000000..89daae972 --- /dev/null +++ b/res/anim/push_right_in.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate android:fromXDelta="-100%p" android:toXDelta="0" android:duration="500"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0" android:duration="500" />
+</set>
diff --git a/res/anim/push_right_out.xml b/res/anim/push_right_out.xml new file mode 100644 index 000000000..b4b796b52 --- /dev/null +++ b/res/anim/push_right_out.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <translate android:fromXDelta="0" android:toXDelta="100%p" android:duration="500"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0" android:duration="500" />
+</set>
\ No newline at end of file diff --git a/res/drawable-hdpi-finger/btn_circle_disable.png b/res/drawable-hdpi-finger-v4/btn_circle_disable.png Binary files differindex ae063b545..ae063b545 100644 --- a/res/drawable-hdpi-finger/btn_circle_disable.png +++ b/res/drawable-hdpi-finger-v4/btn_circle_disable.png diff --git a/res/drawable-hdpi-finger/btn_circle_disable_focused.png b/res/drawable-hdpi-finger-v4/btn_circle_disable_focused.png Binary files differindex 7a5d4fe4e..7a5d4fe4e 100644 --- a/res/drawable-hdpi-finger/btn_circle_disable_focused.png +++ b/res/drawable-hdpi-finger-v4/btn_circle_disable_focused.png diff --git a/res/drawable-hdpi-finger/btn_circle_normal.png b/res/drawable-hdpi-finger-v4/btn_circle_normal.png Binary files differindex 5eda66883..5eda66883 100644 --- a/res/drawable-hdpi-finger/btn_circle_normal.png +++ b/res/drawable-hdpi-finger-v4/btn_circle_normal.png diff --git a/res/drawable-hdpi-finger/btn_circle_pressed.png b/res/drawable-hdpi-finger-v4/btn_circle_pressed.png Binary files differindex 88848bac2..88848bac2 100644 --- a/res/drawable-hdpi-finger/btn_circle_pressed.png +++ b/res/drawable-hdpi-finger-v4/btn_circle_pressed.png diff --git a/res/drawable-hdpi-finger/btn_circle_selected.png b/res/drawable-hdpi-finger-v4/btn_circle_selected.png Binary files differindex 74690705f..74690705f 100644 --- a/res/drawable-hdpi-finger/btn_circle_selected.png +++ b/res/drawable-hdpi-finger-v4/btn_circle_selected.png diff --git a/res/drawable-hdpi-finger/ic_btn_round_minus.png b/res/drawable-hdpi-finger-v4/ic_btn_round_minus.png Binary files differindex 27af3faf4..27af3faf4 100644 --- a/res/drawable-hdpi-finger/ic_btn_round_minus.png +++ b/res/drawable-hdpi-finger-v4/ic_btn_round_minus.png diff --git a/res/drawable-hdpi-finger/ic_btn_round_plus.png b/res/drawable-hdpi-finger-v4/ic_btn_round_plus.png Binary files differindex b24168c32..b24168c32 100644 --- a/res/drawable-hdpi-finger/ic_btn_round_plus.png +++ b/res/drawable-hdpi-finger-v4/ic_btn_round_plus.png diff --git a/res/drawable-hdpi/encrypted.png b/res/drawable-hdpi-v4/encrypted.png Binary files differindex 6d7c616a4..6d7c616a4 100644 --- a/res/drawable-hdpi/encrypted.png +++ b/res/drawable-hdpi-v4/encrypted.png diff --git a/res/drawable-hdpi/encrypted_large.png b/res/drawable-hdpi-v4/encrypted_large.png Binary files differindex dc7466e45..dc7466e45 100644 --- a/res/drawable-hdpi/encrypted_large.png +++ b/res/drawable-hdpi-v4/encrypted_large.png diff --git a/res/drawable-hdpi/encrypted_small.png b/res/drawable-hdpi-v4/encrypted_small.png Binary files differindex 5ed9fe4b8..5ed9fe4b8 100644 --- a/res/drawable-hdpi/encrypted_small.png +++ b/res/drawable-hdpi-v4/encrypted_small.png diff --git a/res/drawable-hdpi-v4/ic_next.png b/res/drawable-hdpi-v4/ic_next.png Binary files differnew file mode 100644 index 000000000..d71058055 --- /dev/null +++ b/res/drawable-hdpi-v4/ic_next.png diff --git a/res/drawable-hdpi-v4/ic_previous.png b/res/drawable-hdpi-v4/ic_previous.png Binary files differnew file mode 100644 index 000000000..d610e4667 --- /dev/null +++ b/res/drawable-hdpi-v4/ic_previous.png diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi-v4/icon.png Binary files differindex 9e2e7c0e4..9e2e7c0e4 100644 --- a/res/drawable-hdpi/icon.png +++ b/res/drawable-hdpi-v4/icon.png diff --git a/res/drawable-hdpi/key.png b/res/drawable-hdpi-v4/key.png Binary files differindex 6f18c0240..6f18c0240 100644 --- a/res/drawable-hdpi/key.png +++ b/res/drawable-hdpi-v4/key.png diff --git a/res/drawable-hdpi/key_large.png b/res/drawable-hdpi-v4/key_large.png Binary files differindex 81816835d..81816835d 100644 --- a/res/drawable-hdpi/key_large.png +++ b/res/drawable-hdpi-v4/key_large.png diff --git a/res/drawable-hdpi/key_small.png b/res/drawable-hdpi-v4/key_small.png Binary files differindex 3f42a0d9b..3f42a0d9b 100644 --- a/res/drawable-hdpi/key_small.png +++ b/res/drawable-hdpi-v4/key_small.png diff --git a/res/drawable-hdpi/overlay_error.png b/res/drawable-hdpi-v4/overlay_error.png Binary files differindex db6a08329..db6a08329 100644 --- a/res/drawable-hdpi/overlay_error.png +++ b/res/drawable-hdpi-v4/overlay_error.png diff --git a/res/drawable-hdpi/overlay_ok.png b/res/drawable-hdpi-v4/overlay_ok.png Binary files differindex 33dc08094..33dc08094 100644 --- a/res/drawable-hdpi/overlay_ok.png +++ b/res/drawable-hdpi-v4/overlay_ok.png diff --git a/res/drawable-hdpi/signed.png b/res/drawable-hdpi-v4/signed.png Binary files differindex 92e64dc51..92e64dc51 100644 --- a/res/drawable-hdpi/signed.png +++ b/res/drawable-hdpi-v4/signed.png diff --git a/res/drawable-hdpi/signed_large.png b/res/drawable-hdpi-v4/signed_large.png Binary files differindex 53d8ac991..53d8ac991 100644 --- a/res/drawable-hdpi/signed_large.png +++ b/res/drawable-hdpi-v4/signed_large.png diff --git a/res/drawable-hdpi/signed_small.png b/res/drawable-hdpi-v4/signed_small.png Binary files differindex d7f147f05..d7f147f05 100644 --- a/res/drawable-hdpi/signed_small.png +++ b/res/drawable-hdpi-v4/signed_small.png diff --git a/res/drawable-ldpi/encrypted.png b/res/drawable-ldpi-v4/encrypted.png Binary files differindex 7f4ab803f..7f4ab803f 100644 --- a/res/drawable-ldpi/encrypted.png +++ b/res/drawable-ldpi-v4/encrypted.png diff --git a/res/drawable-ldpi/encrypted_large.png b/res/drawable-ldpi-v4/encrypted_large.png Binary files differindex 2783804bc..2783804bc 100644 --- a/res/drawable-ldpi/encrypted_large.png +++ b/res/drawable-ldpi-v4/encrypted_large.png diff --git a/res/drawable-ldpi/encrypted_small.png b/res/drawable-ldpi-v4/encrypted_small.png Binary files differindex 0ffedf2dd..0ffedf2dd 100644 --- a/res/drawable-ldpi/encrypted_small.png +++ b/res/drawable-ldpi-v4/encrypted_small.png diff --git a/res/drawable-ldpi-v4/ic_next.png b/res/drawable-ldpi-v4/ic_next.png Binary files differnew file mode 100644 index 000000000..474ed8faa --- /dev/null +++ b/res/drawable-ldpi-v4/ic_next.png diff --git a/res/drawable-ldpi-v4/ic_previous.png b/res/drawable-ldpi-v4/ic_previous.png Binary files differnew file mode 100644 index 000000000..6fd885e6b --- /dev/null +++ b/res/drawable-ldpi-v4/ic_previous.png diff --git a/res/drawable-ldpi/icon.png b/res/drawable-ldpi-v4/icon.png Binary files differindex 9d44341f1..9d44341f1 100644 --- a/res/drawable-ldpi/icon.png +++ b/res/drawable-ldpi-v4/icon.png diff --git a/res/drawable-ldpi/key.png b/res/drawable-ldpi-v4/key.png Binary files differindex 121803508..121803508 100644 --- a/res/drawable-ldpi/key.png +++ b/res/drawable-ldpi-v4/key.png diff --git a/res/drawable-ldpi/key_large.png b/res/drawable-ldpi-v4/key_large.png Binary files differindex de7e72524..de7e72524 100644 --- a/res/drawable-ldpi/key_large.png +++ b/res/drawable-ldpi-v4/key_large.png diff --git a/res/drawable-ldpi/key_small.png b/res/drawable-ldpi-v4/key_small.png Binary files differindex 1763c4256..1763c4256 100644 --- a/res/drawable-ldpi/key_small.png +++ b/res/drawable-ldpi-v4/key_small.png diff --git a/res/drawable-ldpi/overlay_error.png b/res/drawable-ldpi-v4/overlay_error.png Binary files differindex 568f2b1ee..568f2b1ee 100644 --- a/res/drawable-ldpi/overlay_error.png +++ b/res/drawable-ldpi-v4/overlay_error.png diff --git a/res/drawable-ldpi/overlay_ok.png b/res/drawable-ldpi-v4/overlay_ok.png Binary files differindex db415a846..db415a846 100644 --- a/res/drawable-ldpi/overlay_ok.png +++ b/res/drawable-ldpi-v4/overlay_ok.png diff --git a/res/drawable-ldpi/signed.png b/res/drawable-ldpi-v4/signed.png Binary files differindex 590220281..590220281 100644 --- a/res/drawable-ldpi/signed.png +++ b/res/drawable-ldpi-v4/signed.png diff --git a/res/drawable-ldpi/signed_large.png b/res/drawable-ldpi-v4/signed_large.png Binary files differindex 490e94fbd..490e94fbd 100644 --- a/res/drawable-ldpi/signed_large.png +++ b/res/drawable-ldpi-v4/signed_large.png diff --git a/res/drawable-ldpi/signed_small.png b/res/drawable-ldpi-v4/signed_small.png Binary files differindex ca33fc1f7..ca33fc1f7 100644 --- a/res/drawable-ldpi/signed_small.png +++ b/res/drawable-ldpi-v4/signed_small.png diff --git a/res/drawable-mdpi-finger/btn_circle_disable.png b/res/drawable-mdpi-finger-v4/btn_circle_disable.png Binary files differindex 33b74a66c..33b74a66c 100644 --- a/res/drawable-mdpi-finger/btn_circle_disable.png +++ b/res/drawable-mdpi-finger-v4/btn_circle_disable.png diff --git a/res/drawable-mdpi-finger/btn_circle_disable_focused.png b/res/drawable-mdpi-finger-v4/btn_circle_disable_focused.png Binary files differindex 005ad8dca..005ad8dca 100644 --- a/res/drawable-mdpi-finger/btn_circle_disable_focused.png +++ b/res/drawable-mdpi-finger-v4/btn_circle_disable_focused.png diff --git a/res/drawable-mdpi-finger/btn_circle_normal.png b/res/drawable-mdpi-finger-v4/btn_circle_normal.png Binary files differindex fc5af1c9f..fc5af1c9f 100644 --- a/res/drawable-mdpi-finger/btn_circle_normal.png +++ b/res/drawable-mdpi-finger-v4/btn_circle_normal.png diff --git a/res/drawable-mdpi-finger/btn_circle_pressed.png b/res/drawable-mdpi-finger-v4/btn_circle_pressed.png Binary files differindex 8f40afdfc..8f40afdfc 100644 --- a/res/drawable-mdpi-finger/btn_circle_pressed.png +++ b/res/drawable-mdpi-finger-v4/btn_circle_pressed.png diff --git a/res/drawable-mdpi-finger/btn_circle_selected.png b/res/drawable-mdpi-finger-v4/btn_circle_selected.png Binary files differindex c74fac227..c74fac227 100644 --- a/res/drawable-mdpi-finger/btn_circle_selected.png +++ b/res/drawable-mdpi-finger-v4/btn_circle_selected.png diff --git a/res/drawable-mdpi-finger/ic_btn_round_minus.png b/res/drawable-mdpi-finger-v4/ic_btn_round_minus.png Binary files differindex 96dbb17d2..96dbb17d2 100644 --- a/res/drawable-mdpi-finger/ic_btn_round_minus.png +++ b/res/drawable-mdpi-finger-v4/ic_btn_round_minus.png diff --git a/res/drawable-mdpi-finger/ic_btn_round_plus.png b/res/drawable-mdpi-finger-v4/ic_btn_round_plus.png Binary files differindex 1ec8a956a..1ec8a956a 100644 --- a/res/drawable-mdpi-finger/ic_btn_round_plus.png +++ b/res/drawable-mdpi-finger-v4/ic_btn_round_plus.png diff --git a/res/drawable-mdpi/encrypted.png b/res/drawable-mdpi-v4/encrypted.png Binary files differindex 2783804bc..2783804bc 100644 --- a/res/drawable-mdpi/encrypted.png +++ b/res/drawable-mdpi-v4/encrypted.png diff --git a/res/drawable-mdpi/encrypted_large.png b/res/drawable-mdpi-v4/encrypted_large.png Binary files differindex 6d7c616a4..6d7c616a4 100644 --- a/res/drawable-mdpi/encrypted_large.png +++ b/res/drawable-mdpi-v4/encrypted_large.png diff --git a/res/drawable-mdpi/encrypted_small.png b/res/drawable-mdpi-v4/encrypted_small.png Binary files differindex 7f4ab803f..7f4ab803f 100644 --- a/res/drawable-mdpi/encrypted_small.png +++ b/res/drawable-mdpi-v4/encrypted_small.png diff --git a/res/drawable-mdpi-v4/ic_next.png b/res/drawable-mdpi-v4/ic_next.png Binary files differnew file mode 100644 index 000000000..8271c1380 --- /dev/null +++ b/res/drawable-mdpi-v4/ic_next.png diff --git a/res/drawable-mdpi-v4/ic_previous.png b/res/drawable-mdpi-v4/ic_previous.png Binary files differnew file mode 100644 index 000000000..ef90db972 --- /dev/null +++ b/res/drawable-mdpi-v4/ic_previous.png diff --git a/res/drawable-mdpi/icon.png b/res/drawable-mdpi-v4/icon.png Binary files differindex b4e4db40e..b4e4db40e 100644 --- a/res/drawable-mdpi/icon.png +++ b/res/drawable-mdpi-v4/icon.png diff --git a/res/drawable-mdpi/key.png b/res/drawable-mdpi-v4/key.png Binary files differindex de7e72524..de7e72524 100644 --- a/res/drawable-mdpi/key.png +++ b/res/drawable-mdpi-v4/key.png diff --git a/res/drawable-mdpi/key_large.png b/res/drawable-mdpi-v4/key_large.png Binary files differindex 6f18c0240..6f18c0240 100644 --- a/res/drawable-mdpi/key_large.png +++ b/res/drawable-mdpi-v4/key_large.png diff --git a/res/drawable-mdpi/key_small.png b/res/drawable-mdpi-v4/key_small.png Binary files differindex 121803508..121803508 100644 --- a/res/drawable-mdpi/key_small.png +++ b/res/drawable-mdpi-v4/key_small.png diff --git a/res/drawable-mdpi/overlay_error.png b/res/drawable-mdpi-v4/overlay_error.png Binary files differindex 2372de59e..2372de59e 100644 --- a/res/drawable-mdpi/overlay_error.png +++ b/res/drawable-mdpi-v4/overlay_error.png diff --git a/res/drawable-mdpi/overlay_ok.png b/res/drawable-mdpi-v4/overlay_ok.png Binary files differindex 2f0005898..2f0005898 100644 --- a/res/drawable-mdpi/overlay_ok.png +++ b/res/drawable-mdpi-v4/overlay_ok.png diff --git a/res/drawable-mdpi/signed.png b/res/drawable-mdpi-v4/signed.png Binary files differindex 490e94fbd..490e94fbd 100644 --- a/res/drawable-mdpi/signed.png +++ b/res/drawable-mdpi-v4/signed.png diff --git a/res/drawable-mdpi/signed_large.png b/res/drawable-mdpi-v4/signed_large.png Binary files differindex 92e64dc51..92e64dc51 100644 --- a/res/drawable-mdpi/signed_large.png +++ b/res/drawable-mdpi-v4/signed_large.png diff --git a/res/drawable-mdpi/signed_small.png b/res/drawable-mdpi-v4/signed_small.png Binary files differindex 590220281..590220281 100644 --- a/res/drawable-mdpi/signed_small.png +++ b/res/drawable-mdpi-v4/signed_small.png diff --git a/res/drawable/btn_circle_disable.png b/res/drawable/btn_circle_disable.png Binary files differnew file mode 100644 index 000000000..33b74a66c --- /dev/null +++ b/res/drawable/btn_circle_disable.png diff --git a/res/drawable/btn_circle_disable_focused.png b/res/drawable/btn_circle_disable_focused.png Binary files differnew file mode 100644 index 000000000..005ad8dca --- /dev/null +++ b/res/drawable/btn_circle_disable_focused.png diff --git a/res/drawable/btn_circle_normal.png b/res/drawable/btn_circle_normal.png Binary files differnew file mode 100644 index 000000000..fc5af1c9f --- /dev/null +++ b/res/drawable/btn_circle_normal.png diff --git a/res/drawable/btn_circle_pressed.png b/res/drawable/btn_circle_pressed.png Binary files differnew file mode 100644 index 000000000..8f40afdfc --- /dev/null +++ b/res/drawable/btn_circle_pressed.png diff --git a/res/drawable/btn_circle_selected.png b/res/drawable/btn_circle_selected.png Binary files differnew file mode 100644 index 000000000..c74fac227 --- /dev/null +++ b/res/drawable/btn_circle_selected.png diff --git a/res/drawable/encrypted.png b/res/drawable/encrypted.png Binary files differnew file mode 100644 index 000000000..2783804bc --- /dev/null +++ b/res/drawable/encrypted.png diff --git a/res/drawable/encrypted_large.png b/res/drawable/encrypted_large.png Binary files differnew file mode 100644 index 000000000..6d7c616a4 --- /dev/null +++ b/res/drawable/encrypted_large.png diff --git a/res/drawable/encrypted_small.png b/res/drawable/encrypted_small.png Binary files differnew file mode 100644 index 000000000..7f4ab803f --- /dev/null +++ b/res/drawable/encrypted_small.png diff --git a/res/drawable/ic_btn_round_minus.png b/res/drawable/ic_btn_round_minus.png Binary files differnew file mode 100644 index 000000000..96dbb17d2 --- /dev/null +++ b/res/drawable/ic_btn_round_minus.png diff --git a/res/drawable/ic_btn_round_plus.png b/res/drawable/ic_btn_round_plus.png Binary files differnew file mode 100644 index 000000000..1ec8a956a --- /dev/null +++ b/res/drawable/ic_btn_round_plus.png diff --git a/res/drawable/ic_launcher_folder.png b/res/drawable/ic_launcher_folder.png Binary files differnew file mode 100644 index 000000000..ed31ba580 --- /dev/null +++ b/res/drawable/ic_launcher_folder.png diff --git a/res/drawable/ic_launcher_folder_small.png b/res/drawable/ic_launcher_folder_small.png Binary files differnew file mode 100644 index 000000000..5df8d60f0 --- /dev/null +++ b/res/drawable/ic_launcher_folder_small.png diff --git a/res/drawable/ic_next.png b/res/drawable/ic_next.png Binary files differnew file mode 100644 index 000000000..8271c1380 --- /dev/null +++ b/res/drawable/ic_next.png diff --git a/res/drawable/ic_previous.png b/res/drawable/ic_previous.png Binary files differnew file mode 100644 index 000000000..ef90db972 --- /dev/null +++ b/res/drawable/ic_previous.png diff --git a/res/drawable/icon.png b/res/drawable/icon.png Binary files differnew file mode 100644 index 000000000..b4e4db40e --- /dev/null +++ b/res/drawable/icon.png diff --git a/res/drawable/key.png b/res/drawable/key.png Binary files differnew file mode 100644 index 000000000..de7e72524 --- /dev/null +++ b/res/drawable/key.png diff --git a/res/drawable/key_large.png b/res/drawable/key_large.png Binary files differnew file mode 100644 index 000000000..6f18c0240 --- /dev/null +++ b/res/drawable/key_large.png diff --git a/res/drawable/key_small.png b/res/drawable/key_small.png Binary files differnew file mode 100644 index 000000000..121803508 --- /dev/null +++ b/res/drawable/key_small.png diff --git a/res/drawable/overlay_error.png b/res/drawable/overlay_error.png Binary files differnew file mode 100644 index 000000000..2372de59e --- /dev/null +++ b/res/drawable/overlay_error.png diff --git a/res/drawable/overlay_ok.png b/res/drawable/overlay_ok.png Binary files differnew file mode 100644 index 000000000..2f0005898 --- /dev/null +++ b/res/drawable/overlay_ok.png diff --git a/res/drawable/signed.png b/res/drawable/signed.png Binary files differnew file mode 100644 index 000000000..490e94fbd --- /dev/null +++ b/res/drawable/signed.png diff --git a/res/drawable/signed_large.png b/res/drawable/signed_large.png Binary files differnew file mode 100644 index 000000000..92e64dc51 --- /dev/null +++ b/res/drawable/signed_large.png diff --git a/res/drawable/signed_small.png b/res/drawable/signed_small.png Binary files differnew file mode 100644 index 000000000..590220281 --- /dev/null +++ b/res/drawable/signed_small.png diff --git a/res/layout/account_item.xml b/res/layout/account_item.xml index e37000ff0..0aa76719a 100644 --- a/res/layout/account_item.xml +++ b/res/layout/account_item.xml @@ -24,12 +24,12 @@ android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight"> -<TextView - android:id="@+id/account_name" - android:text="someone@gmail.com" - android:textAppearance="?android:attr/textAppearanceLarge" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical"/> + <TextView + android:id="@+id/accountName" + android:text="someone@gmail.com" + android:textAppearance="?android:attr/textAppearanceLarge" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> </LinearLayout> diff --git a/res/layout/create_key.xml b/res/layout/create_key.xml index 569b703f5..ab327ffeb 100644 --- a/res/layout/create_key.xml +++ b/res/layout/create_key.xml @@ -18,35 +18,47 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="fill_parent" android:layout_width="fill_parent"> + <TableLayout android:layout_height="fill_parent" android:layout_width="fill_parent" android:stretchColumns="1" android:layout_marginRight="?android:attr/scrollbarSize" android:paddingLeft="6dip"> + <TableRow> + <TextView android:id="@+id/label_algorithm" android:text="Algorithm" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center_vertical" android:paddingRight="10dip"/> + <Spinner android:id="@+id/algorithm" android:layout_width="fill_parent" android:layout_height="wrap_content"/> + </TableRow> + <TableRow> + <TextView android:id="@+id/label_size" android:text="Key Size" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center_vertical" android:paddingRight="10dip"/> + <EditText android:id="@+id/size" android:text="1024" android:layout_height="wrap_content" - android:layout_width="fill_parent" android:gravity="right" android:numeric="integer"/> + android:layout_width="fill_parent" + android:gravity="right" + android:numeric="integer"/> </TableRow> + </TableLayout> + </ScrollView> diff --git a/res/layout/decrypt.xml b/res/layout/decrypt.xml new file mode 100644 index 000000000..03e2f6311 --- /dev/null +++ b/res/layout/decrypt.xml @@ -0,0 +1,214 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:fillViewport="true"> + + <ScrollView + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1" + android:fillViewport="true"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" + android:layout_marginLeft="5dip"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <ImageView + android:id="@+id/sourcePrevious" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_previous"/> + + <TextView + android:id="@+id/sourceLabel" + android:layout_width="0dip" + android:layout_height="fill_parent" + android:layout_weight="1" + android:text="@string/label_message" + android:textAppearance="?android:attr/textAppearanceMedium" + android:gravity="center_horizontal|center_vertical" + android:textColor="#ffffffff"/> + + <ImageView + android:id="@+id/sourceNext" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_next"/> + + </LinearLayout> + + <ViewFlipper + android:id="@+id/source" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1"> + + <LinearLayout + android:id="@+id/sourceMessage" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical"> + + <EditText + android:id="@+id/message" + android:inputType="text|textCapSentences|textMultiLine|textLongMessage" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="top"/> + + </LinearLayout> + + <LinearLayout + android:id="@+id/sourceFile" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <EditText + android:id="@+id/filename" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1"/> + + <ImageButton + android:id="@+id/btn_browse" + android:src="@drawable/ic_launcher_folder_small" + android:layout_height="wrap_content" + android:layout_width="wrap_content"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_deleteAfterDecryption" + android:text="@string/label_deleteAfterDecryption" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_gravity="center_vertical" + android:paddingRight="10dip" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1"/> + + <CheckBox + android:id="@+id/deleteAfterDecryption" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + </LinearLayout> + + </ViewFlipper> + + </LinearLayout> + + </ScrollView> + + <LinearLayout + android:id="@+id/signature" + android:orientation="horizontal" + android:layout_height="wrap_content" + android:layout_width="fill_parent"> + + <RelativeLayout + android:layout_height="wrap_content" + android:layout_width="wrap_content"> + + <ImageView + android:id="@+id/ic_signature" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/signed_large"/> + + <ImageView + android:id="@+id/ic_signature_status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/overlay_error"/> + + </RelativeLayout> + + <LinearLayout + android:orientation="vertical" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingLeft="5dip"> + + <TextView + android:id="@+id/mainUserId" + android:text="Main User Id" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="left"/> + + <TextView + android:id="@+id/mainUserIdRest" + android:text="Main User Id Rest" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="left"/> + + </LinearLayout> + + </LinearLayout> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + style="@android:style/ButtonBar"> + + <Button + android:id="@+id/btn_reply" + android:text="@string/btn_reply" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1"/> + + <Button + android:id="@+id/btn_decrypt" + android:text="@string/btn_decrypt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1"/> + + </LinearLayout> + +</LinearLayout> diff --git a/res/layout/decrypt_message.xml b/res/layout/decrypt_message.xml deleted file mode 100644 index 2a0aa153d..000000000 --- a/res/layout/decrypt_message.xml +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:fillViewport="true"> - -<EditText - android:id="@+id/message" - android:inputType="text|textCapSentences|textMultiLine|textLongMessage" - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1" - android:gravity="top"/> - -<LinearLayout - android:orientation="horizontal" - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:paddingLeft="5dip" - android:paddingRight="5dip"> - -<LinearLayout - android:id="@+id/layout_signature" - android:orientation="horizontal" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_weight="2"> - -<RelativeLayout - android:layout_height="wrap_content" - android:layout_width="wrap_content"> -<ImageView - android:id="@+id/ic_signature" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/signed_large"/> - -<ImageView - android:id="@+id/ic_signature_status" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/overlay_error"/> - -</RelativeLayout> - -<LinearLayout - android:orientation="vertical" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingLeft="5dip"> - -<TextView - android:id="@+id/main_user_id" - android:text="Main User Id" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="left"/> - -<TextView - android:id="@+id/main_user_id_rest" - android:text="Main User Id Rest" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content" android:layout_gravity="left"/> - -</LinearLayout> -</LinearLayout> - -<Button - android:id="@+id/btn_decrypt" - android:text="@string/btn_decrypt" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1"/> - -</LinearLayout> - -</LinearLayout> - diff --git a/res/layout/edit_key.xml b/res/layout/edit_key.xml index 2fceeb5a3..bf994fa44 100644 --- a/res/layout/edit_key.xml +++ b/res/layout/edit_key.xml @@ -22,19 +22,21 @@ android:paddingTop="5dip" android:fillViewport="true"> -<ScrollView - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1"> -<LinearLayout - android:id="@+id/container" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:orientation="vertical" - android:layout_marginRight="?android:attr/scrollbarSize"/> -</ScrollView> + <ScrollView + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1"> -<LinearLayout + <LinearLayout + android:id="@+id/container" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" + android:layout_marginRight="?android:attr/scrollbarSize"/> + + </ScrollView> + + <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" @@ -53,6 +55,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/btn_doNotSave"/> -</LinearLayout> + + </LinearLayout> </LinearLayout> diff --git a/res/layout/edit_key_key_item.xml b/res/layout/edit_key_key_item.xml index 46de4a977..ba428938e 100644 --- a/res/layout/edit_key_key_item.xml +++ b/res/layout/edit_key_key_item.xml @@ -15,99 +15,129 @@ --> <org.thialfihar.android.apg.ui.widget.KeyEditor - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingLeft="5dip"> - -<View - android:id="@+id/separator" - android:layout_width="fill_parent" - android:layout_height="1dip" - android:background="?android:attr/listDivider"/> - -<LinearLayout - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:orientation="horizontal"> - <TableLayout - android:layout_height="wrap_content" - android:layout_width="0dip" - android:layout_weight="1" - android:layout_marginLeft="16dip" - android:stretchColumns="1"> - <TableRow> - <TextView android:id="@+id/label_key_id" android:text="Key ID" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:paddingRight="10dip"/> - <TextView - android:id="@+id/key_id" - android:text="00000000 00000000" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingRight="5dip" - android:typeface="monospace"/> - </TableRow> - <TableRow> - <TextView android:id="@+id/label_algorithm" - android:text="Algorithm" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:paddingRight="10dip"/> - <TextView android:id="@+id/algorithm" - android:text="Name" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingRight="5dip"/> - </TableRow> - <TableRow> - <TextView android:id="@+id/label_creation" - android:text="Creation" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:paddingRight="10dip"/> - <TextView - android:id="@+id/creation" - android:layout_width="fill_parent" - android:layout_height="wrap_content"/> - </TableRow> - <TableRow> - <TextView android:id="@+id/label_expiry" - android:text="Expiry" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:paddingRight="10dip"/> - <Button - android:id="@+id/expiry" - android:layout_width="fill_parent" - android:layout_height="wrap_content"/> - </TableRow> - <TableRow> - <TextView android:id="@+id/label_usage" - android:text="Usage" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_gravity="center_vertical" - android:paddingRight="10dip"/> - <Spinner - android:id="@+id/usage" - android:layout_width="fill_parent" - android:layout_height="wrap_content"/> - </TableRow> - </TableLayout> - - <ImageButton - android:id="@+id/edit_delete" - android:layout_width="wrap_content" + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingLeft="5dip"> + + <View + android:id="@+id/separator" + android:layout_width="fill_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider"/> + + <LinearLayout android:layout_height="wrap_content" - style="@style/MinusButton" - android:layout_gravity="center_vertical"/> + android:layout_width="fill_parent" + android:orientation="horizontal"> + + <TableLayout + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_marginLeft="16dip" + android:stretchColumns="1"> + + <TableRow> + + <TextView + android:id="@+id/label_keyId" + android:text="Key ID" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <TextView + android:id="@+id/keyId" + android:text="00000000 00000000" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingRight="5dip" + android:typeface="monospace"/> + + </TableRow> + + <TableRow> + + <TextView + android:id="@+id/label_algorithm" + android:text="Algorithm" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <TextView + android:id="@+id/algorithm" + android:text="Name" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingRight="5dip"/> + + </TableRow> + + <TableRow> + + <TextView + android:id="@+id/label_creation" + android:text="Creation" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <TextView + android:id="@+id/creation" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + </TableRow> + + <TableRow> + + <TextView + android:id="@+id/label_expiry" + android:text="Expiry" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Button + android:id="@+id/expiry" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + </TableRow> + + <TableRow> + + <TextView + android:id="@+id/label_usage" + android:text="Usage" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Spinner + android:id="@+id/usage" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + </TableRow> + + </TableLayout> + + <ImageButton + android:id="@+id/delete" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/MinusButton" + android:layout_gravity="center_vertical"/> + + </LinearLayout> -</LinearLayout> </org.thialfihar.android.apg.ui.widget.KeyEditor> diff --git a/res/layout/edit_key_section.xml b/res/layout/edit_key_section.xml index b3a48f87e..e57b3b8df 100644 --- a/res/layout/edit_key_section.xml +++ b/res/layout/edit_key_section.xml @@ -15,7 +15,7 @@ --> <org.thialfihar.android.apg.ui.widget.SectionView - xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> diff --git a/res/layout/edit_key_user_id_item.xml b/res/layout/edit_key_user_id_item.xml index 998c436cb..6164cf767 100644 --- a/res/layout/edit_key_user_id_item.xml +++ b/res/layout/edit_key_user_id_item.xml @@ -15,82 +15,99 @@ --> <org.thialfihar.android.apg.ui.widget.UserIdEditor - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingLeft="5dip"> - -<View - android:id="@+id/separator" - android:layout_width="fill_parent" - android:layout_height="1dip" - android:background="?android:attr/listDivider"/> - -<RadioButton - android:id="@+id/is_main_user_id" android:text="Main User ID" - android:layout_height="wrap_content" android:layout_width="wrap_content" - android:layout_marginLeft="20dip"/> - -<LinearLayout - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:orientation="horizontal"> - <TableLayout - android:layout_height="wrap_content" - android:layout_width="0dip" - android:layout_weight="1" - android:layout_marginLeft="16dip"> - <TableRow> - <TextView - android:id="@+id/name_label" - android:text="Name" - android:layout_gravity="center_vertical" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingRight="5dip"/> - <EditText - android:id="@+id/name" - android:layout_weight="1" - android:layout_height="wrap_content" - android:layout_width="fill_parent"/> - </TableRow> - <TableRow> - <TextView - android:id="@+id/email_label" - android:text="Email" - android:layout_gravity="center_vertical" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingRight="5dip"/> - <EditText - android:id="@+id/email" - android:layout_weight="1" - android:layout_height="wrap_content" - android:layout_width="fill_parent"/> - </TableRow> - <TableRow> - <TextView - android:id="@+id/comment_label" - android:text="Comment" - android:layout_gravity="center_vertical" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingRight="5dip"/> - <EditText - android:id="@+id/comment" - android:layout_weight="1" - android:layout_height="wrap_content" - android:layout_width="fill_parent"/> - </TableRow> - </TableLayout> - - <ImageButton - android:id="@+id/edit_delete" + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingLeft="5dip"> + + <View + android:id="@+id/separator" + android:layout_width="fill_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider"/> + + <RadioButton + android:id="@+id/isMainUserId" + android:text="Main User ID" + android:layout_height="wrap_content" android:layout_width="wrap_content" + android:layout_marginLeft="20dip"/> + + <LinearLayout android:layout_height="wrap_content" - style="@style/MinusButton" - android:layout_gravity="center_vertical"/> + android:layout_width="fill_parent" + android:orientation="horizontal"> + + <TableLayout + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_marginLeft="16dip"> + + <TableRow> + + <TextView + android:id="@+id/label_name" + android:text="Name" + android:layout_gravity="center_vertical" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingRight="5dip"/> + + <EditText + android:id="@+id/name" + android:layout_weight="1" + android:layout_height="wrap_content" + android:layout_width="fill_parent"/> + + </TableRow> + + <TableRow> + + <TextView + android:id="@+id/label_email" + android:text="Email" + android:layout_gravity="center_vertical" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingRight="5dip"/> + + <EditText + android:id="@+id/email" + android:layout_weight="1" + android:layout_height="wrap_content" + android:layout_width="fill_parent"/> + + </TableRow> + + <TableRow> + + <TextView + android:id="@+id/label_comment" + android:text="Comment" + android:layout_gravity="center_vertical" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingRight="5dip"/> + + <EditText + android:id="@+id/comment" + android:layout_weight="1" + android:layout_height="wrap_content" + android:layout_width="fill_parent"/> + + </TableRow> + + </TableLayout> + + <ImageButton + android:id="@+id/delete" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/MinusButton" + android:layout_gravity="center_vertical"/> + + </LinearLayout> -</LinearLayout> </org.thialfihar.android.apg.ui.widget.UserIdEditor> diff --git a/res/layout/encrypt.xml b/res/layout/encrypt.xml new file mode 100644 index 000000000..dd51318c2 --- /dev/null +++ b/res/layout/encrypt.xml @@ -0,0 +1,382 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" + android:paddingTop="5dip"> + + <ScrollView + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1" + android:fillViewport="true"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" + android:layout_marginLeft="5dip"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <ImageView + android:id="@+id/sourcePrevious" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_previous"/> + + <TextView + android:id="@+id/sourceLabel" + android:layout_width="0dip" + android:layout_height="fill_parent" + android:layout_weight="1" + android:text="@string/label_message" + android:textAppearance="?android:attr/textAppearanceMedium" + android:gravity="center_horizontal|center_vertical" + android:textColor="#ffffffff"/> + + <ImageView + android:id="@+id/sourceNext" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_next"/> + + </LinearLayout> + + <ViewFlipper + android:id="@+id/source" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1"> + + <LinearLayout + android:id="@+id/sourceMessage" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical"> + + <EditText + android:id="@+id/message" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="top" + android:inputType="text|textCapSentences|textMultiLine|textLongMessage"/> + + </LinearLayout> + + <LinearLayout + android:id="@+id/sourceFile" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <EditText + android:id="@+id/filename" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1"/> + + <ImageButton + android:id="@+id/btn_browse" + android:src="@drawable/ic_launcher_folder_small" + android:layout_height="wrap_content" + android:layout_width="wrap_content"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_fileCompression" + android:text="@string/label_fileCompression" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Spinner + android:id="@+id/fileCompression" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_deleteAfterEncryption" + android:text="@string/label_deleteAfterEncryption" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_gravity="center_vertical" + android:paddingRight="10dip" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1"/> + + <CheckBox + android:id="@+id/deleteAfterEncryption" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_asciiArmour" + android:text="@string/label_asciiArmour" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_gravity="center_vertical" + android:paddingRight="10dip" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1"/> + + <CheckBox + android:id="@+id/asciiArmour" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + </LinearLayout> + + </ViewFlipper> + + <View + android:layout_width="fill_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider" + android:layout_marginBottom="5dip"/> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <ImageView + android:id="@+id/modePrevious" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_previous"/> + + <TextView + android:id="@+id/modeLabel" + android:layout_width="0dip" + android:layout_height="fill_parent" + android:layout_weight="1" + android:text="@string/label_asymmetric" + android:textAppearance="?android:attr/textAppearanceMedium" + android:gravity="center_horizontal|center_vertical" + android:textColor="#ffffffff"/> + + <ImageView + android:id="@+id/modeNext" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_next"/> + + </LinearLayout> + + <ViewFlipper + android:id="@+id/mode" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + + <LinearLayout + android:id="@+id/modeAsymmetric" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_sign" + android:text="@string/label_sign" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + <LinearLayout + android:orientation="vertical" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="5dip"> + + <TextView + android:id="@+id/mainUserId" + android:text="Main User Id" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right"/> + + <TextView + android:id="@+id/mainUserIdRest" + android:text="Main User Id Rest" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right"/> + + </LinearLayout> + + <CheckBox + android:id="@+id/sign" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingBottom="3dip" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_selectPublicKeys" + android:text="@string/label_selectPublicKeys" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_gravity="center_vertical"/> + + <Button + android:text="@string/btn_selectEncryptKeys" + android:id="@+id/btn_selectEncryptKeys" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + </LinearLayout> + + <TableLayout + android:id="@+id/modeSymmetric" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:stretchColumns="1"> + + <TableRow> + + <TextView + android:id="@+id/label_passPhrase" + android:text="@string/label_passPhrase" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <EditText + android:id="@+id/passPhrase" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:inputType="textPassword"/> + + </TableRow> + + <TableRow> + + <TextView + android:id="@+id/label_passPhraseAgain" + android:text="@string/label_passPhraseAgain" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <EditText + android:id="@+id/passPhraseAgain" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:inputType="textPassword"/> + + </TableRow> + + </TableLayout> + + </ViewFlipper> + + <View + android:layout_width="fill_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider" + android:layout_marginBottom="5dip"/> + + </LinearLayout> + + </ScrollView> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + style="@android:style/ButtonBar"> + + <Button + android:id="@+id/btn_encryptToClipboard" + android:text="@string/btn_encryptToClipboard" + android:layout_weight="1" + android:layout_width="0dip" + android:layout_height="wrap_content"/> + + <Button + android:id="@+id/btn_encrypt" + android:text="@string/btn_encrypt" + android:layout_weight="1" + android:layout_width="0dip" + android:layout_height="wrap_content"/> + + </LinearLayout> + +</LinearLayout> diff --git a/res/layout/encrypt_message.xml b/res/layout/encrypt_message.xml deleted file mode 100644 index 254552e03..000000000 --- a/res/layout/encrypt_message.xml +++ /dev/null @@ -1,95 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:fillViewport="true"> - -<EditText - android:id="@+id/message" - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1" - android:gravity="top" - android:inputType="text|textCapSentences|textMultiLine|textLongMessage"> -</EditText> - -<LinearLayout - android:layout_height="wrap_content" - android:layout_width="fill_parent" android:paddingBottom="3dip"> - -<CheckBox - android:text="@string/sign" - android:id="@+id/sign" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical"/> - -<LinearLayout - android:orientation="vertical" - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:layout_gravity="center_vertical" - android:paddingRight="5dip"> - -<TextView - android:id="@+id/main_user_id" - android:text="Main User Id" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="right"> -</TextView> - -<TextView - android:id="@+id/main_user_id_rest" - android:text="Main User Id Rest" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content" android:layout_gravity="right"> -</TextView> - -</LinearLayout> -</LinearLayout> - -<LinearLayout - android:orientation="horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - style="@android:style/ButtonBar"> - -<Button - android:text="@string/btn_selectEncryptKeys" - android:id="@+id/btn_selectEncryptKeys" - android:layout_weight="1" - android:layout_width="0dip" - android:layout_height="wrap_content"/> - -<Button - android:id="@+id/btn_send" - android:text="@string/btn_send" - android:layout_weight="1" - android:layout_width="0dip" - android:layout_height="wrap_content"/> - -</LinearLayout> - -</LinearLayout> - - diff --git a/res/layout/file_dialog.xml b/res/layout/file_dialog.xml new file mode 100644 index 000000000..c42d2636e --- /dev/null +++ b/res/layout/file_dialog.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingLeft="5dip" + android:paddingRight="5dip"> + + <EditText + android:id="@+id/input" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1"/> + + <ImageButton + android:id="@+id/btn_browse" + android:src="@drawable/ic_launcher_folder_small" + android:layout_height="wrap_content" + android:layout_width="wrap_content"/> + +</LinearLayout> diff --git a/res/layout/info.xml b/res/layout/info.xml new file mode 100644 index 000000000..ab9e99a5b --- /dev/null +++ b/res/layout/info.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:fillViewport="true" + android:padding="5dip"> + + <TextView + android:id="@+id/message" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textColor="#ffffffff" + android:autoLink="all"/> +</ScrollView> diff --git a/res/layout/key_list.xml b/res/layout/key_list.xml new file mode 100644 index 000000000..f08495368 --- /dev/null +++ b/res/layout/key_list.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:fillViewport="true"> + + <ExpandableListView + android:id="@+id/list" + android:layout_width="fill_parent" + android:layout_height="fill_parent"/> + +</ScrollView> diff --git a/res/layout/key_list_child_item_master_key.xml b/res/layout/key_list_child_item_master_key.xml index 47eba65b5..790fd42f4 100644 --- a/res/layout/key_list_child_item_master_key.xml +++ b/res/layout/key_list_child_item_master_key.xml @@ -19,54 +19,62 @@ android:singleLine="true"
android:paddingLeft="10dip"
android:layout_marginRight="?android:attr/scrollbarSize"
- android:layout_height="?android:attr/listPreferredItemHeight" android:layout_width="fill_parent">
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:layout_width="fill_parent">
-<LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="fill_parent"
- android:orientation="horizontal"
- android:paddingRight="3dip">
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:orientation="horizontal"
+ android:paddingRight="3dip">
-<ImageView
- android:id="@+id/ic_master_key"
- android:src="@drawable/key_small"
- android:paddingRight="6dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:layout_gravity="center_vertical"/>
+ <ImageView
+ android:id="@+id/ic_masterKey"
+ android:src="@drawable/key_small"
+ android:paddingRight="6dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"/>
-<TextView
- android:id="@+id/key_id"
- android:text="Key ID"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:paddingRight="5dip" android:typeface="monospace"/>
+ <TextView
+ android:id="@+id/keyId"
+ android:text="Key ID"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="5dip"
+ android:typeface="monospace"/>
-<TextView
- android:id="@+id/key_details"
- android:text="(RSA, 1024bit)"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/keyDetails"
+ android:text="(RSA, 1024bit)"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <LinearLayout
+ android:gravity="right"
+ android:orientation="horizontal"
+ android:paddingBottom="2dip"
+ android:paddingTop="2dip"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center_vertical">
-<LinearLayout
- android:gravity="right"
- android:orientation="horizontal"
- android:layout_width="fill_parent" android:paddingBottom="2dip" android:paddingTop="2dip" android:layout_height="fill_parent" android:layout_gravity="center_vertical">
+ <ImageView
+ android:id="@+id/ic_encryptKey"
+ android:src="@drawable/encrypted_small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
-<ImageView
- android:id="@+id/ic_encrypt_key"
- android:src="@drawable/encrypted_small"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+ <ImageView
+ android:id="@+id/ic_signKey"
+ android:src="@drawable/signed_small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
-<ImageView
- android:id="@+id/ic_sign_key"
- android:src="@drawable/signed_small"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+ </LinearLayout>
-</LinearLayout>
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
\ No newline at end of file diff --git a/res/layout/key_list_child_item_sub_key.xml b/res/layout/key_list_child_item_sub_key.xml index 085d78f05..ac7c217a6 100644 --- a/res/layout/key_list_child_item_sub_key.xml +++ b/res/layout/key_list_child_item_sub_key.xml @@ -22,49 +22,51 @@ android:layout_height="?android:attr/listPreferredItemHeight" android:layout_width="fill_parent"> -<LinearLayout - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:orientation="horizontal" - android:paddingRight="3dip"> + <LinearLayout + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:orientation="horizontal" + android:paddingRight="3dip"> -<TextView - android:id="@+id/key_id" - android:text="Key ID" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content" android:paddingRight="5dip" android:typeface="monospace"/> + <TextView + android:id="@+id/keyId" + android:text="Key ID" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingRight="5dip" + android:typeface="monospace"/> -<TextView - android:id="@+id/key_details" - android:text="(RSA, 1024bit)" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <TextView + android:id="@+id/keyDetails" + android:text="(RSA, 1024bit)" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <LinearLayout + android:gravity="right" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:paddingBottom="2dip" + android:paddingTop="2dip" + android:layout_gravity="center_vertical"> -<LinearLayout - android:gravity="right" - android:orientation="horizontal" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:paddingBottom="2dip" - android:paddingTop="2dip" - android:layout_gravity="center_vertical"> + <ImageView + android:id="@+id/ic_encryptKey" + android:src="@drawable/encrypted_small" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -<ImageView - android:id="@+id/ic_encrypt_key" - android:src="@drawable/encrypted_small" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <ImageView + android:id="@+id/ic_signKey" + android:src="@drawable/signed_small" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -<ImageView - android:id="@+id/ic_sign_key" - android:src="@drawable/signed_small" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + </LinearLayout> -</LinearLayout> + </LinearLayout> </LinearLayout> -</LinearLayout>
\ No newline at end of file diff --git a/res/layout/key_list_child_item_user_id.xml b/res/layout/key_list_child_item_user_id.xml index 80cdd2867..3226dd58a 100644 --- a/res/layout/key_list_child_item_user_id.xml +++ b/res/layout/key_list_child_item_user_id.xml @@ -22,12 +22,12 @@ android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight">
-<TextView
- android:id="@+id/user_id"
- android:text="User ID"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="3dip"/>
+ <TextView
+ android:id="@+id/userId"
+ android:text="User ID"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="3dip"/>
</LinearLayout>
diff --git a/res/layout/key_list_group_item.xml b/res/layout/key_list_group_item.xml index aaada82e3..35d0ab367 100644 --- a/res/layout/key_list_group_item.xml +++ b/res/layout/key_list_group_item.xml @@ -21,32 +21,33 @@ android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight"> -<LinearLayout - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="wrap_content" android:paddingLeft="36dip"> - -<TextView - android:id="@+id/main_user_id" - android:text="Main User ID" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - -<TextView - android:id="@+id/main_user_id_rest" - android:text="<user@somewhere.com>" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - -</LinearLayout> - -<LinearLayout - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> + <LinearLayout + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingLeft="36dip"> + + <TextView + android:id="@+id/mainUserId" + android:text="Main User ID" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/mainUserIdRest" + android:text="<user@somewhere.com>" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + </LinearLayout> + + <LinearLayout + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + + </LinearLayout> </LinearLayout> - -</LinearLayout>
\ No newline at end of file diff --git a/res/layout/mailbox_message_item.xml b/res/layout/mailbox_message_item.xml index b2b5e91d4..05a267fb6 100644 --- a/res/layout/mailbox_message_item.xml +++ b/res/layout/mailbox_message_item.xml @@ -24,34 +24,34 @@ android:layout_height="?android:attr/listPreferredItemHeight" android:layout_width="fill_parent"> -<ImageView - android:id="@+id/ic_encrypted" - android:src="@drawable/encrypted" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerVertical="true"/> - -<LinearLayout - android:orientation="vertical" - android:paddingLeft="5dip" - android:layout_weight="1" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> - -<TextView - android:id="@+id/subject" - android:text="Subject" - android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - -<TextView - android:id="@+id/email_address" - android:text="user@somewhere.com" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <ImageView + android:id="@+id/ic_status" + android:src="@drawable/encrypted" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + <LinearLayout + android:orientation="vertical" + android:paddingLeft="5dip" + android:layout_weight="1" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/subject" + android:text="Subject" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/emailAddress" + android:text="user@somewhere.com" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + </LinearLayout> </LinearLayout> - -</LinearLayout>
\ No newline at end of file diff --git a/res/layout/main.xml b/res/layout/main.xml index 81c5f224b..f88c393db 100644 --- a/res/layout/main.xml +++ b/res/layout/main.xml @@ -22,40 +22,68 @@ android:paddingTop="5dip" android:fillViewport="true"> -<ScrollView - android:layout_marginTop="10dip" - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1"> + <ScrollView + android:layout_marginTop="10dip" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1" + android:fillViewport="true"> -<ListView - android:id="@+id/account_list" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> -</ListView> + <ListView + android:id="@+id/accounts" + android:layout_width="fill_parent" + android:layout_height="fill_parent"/> -</ScrollView> + </ScrollView> -<LinearLayout - android:orientation="horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - style="@android:style/ButtonBar"> - -<Button - android:id="@+id/btn_encryptMessage" - android:text="@string/btn_encryptMessage" - android:layout_width="wrap_content" - android:layout_weight="1" - android:layout_height="wrap_content"/> - -<Button - android:id="@+id/btn_decryptMessage" - android:text="@string/btn_decryptMessage" - android:layout_width="wrap_content" - android:layout_weight="1" - android:layout_height="wrap_content"/> + <LinearLayout + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + style="@android:style/ButtonBar"> -</LinearLayout> + <LinearLayout + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + + <Button + android:id="@+id/btn_encryptFile" + android:text="@string/btn_encryptFile" + android:layout_width="wrap_content" + android:layout_weight="1" + android:layout_height="wrap_content"/> + + <Button + android:id="@+id/btn_decryptFile" + android:text="@string/btn_decryptFile" + android:layout_width="wrap_content" + android:layout_weight="1" + android:layout_height="wrap_content"/> + + </LinearLayout> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> -</LinearLayout>
\ No newline at end of file + <Button + android:id="@+id/btn_encryptMessage" + android:text="@string/btn_encryptMessage" + android:layout_width="wrap_content" + android:layout_weight="1" + android:layout_height="wrap_content"/> + + <Button + android:id="@+id/btn_decryptMessage" + android:text="@string/btn_decryptMessage" + android:layout_width="wrap_content" + android:layout_weight="1" + android:layout_height="wrap_content"/> + + </LinearLayout> + + </LinearLayout> + +</LinearLayout> diff --git a/res/layout/pass_phrase.xml b/res/layout/pass_phrase.xml new file mode 100644 index 000000000..f377e5bf7 --- /dev/null +++ b/res/layout/pass_phrase.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingLeft="5dip" + android:paddingRight="5dip"> + + <EditText + android:id="@+id/passPhrase" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:inputType="textPassword"/> + + <EditText + android:id="@+id/passPhraseAgain" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:inputType="textPassword"/> + +</LinearLayout> diff --git a/res/layout/preferences.xml b/res/layout/preferences.xml new file mode 100644 index 000000000..1ff97a0e4 --- /dev/null +++ b/res/layout/preferences.xml @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:fillViewport="true"> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" + android:paddingTop="5dip" + android:layout_marginRight="?android:attr/scrollbarSize"> + + <TextView + android:id="@+id/section_general" + android:text="@string/section_general" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge"/> + + <View + android:layout_width="fill_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider" + android:layout_marginBottom="5dip"/> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_passPhraseCacheTtl" + android:text="@string/label_passPhraseCacheTtl" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Spinner + android:id="@+id/passPhraseCacheTtl" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <TextView + android:id="@+id/section_defaults" + android:text="@string/section_defaults" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginTop="5dip" + android:textAppearance="?android:attr/textAppearanceLarge"/> + + <View + android:layout_width="fill_parent" + android:layout_height="1dip" + android:background="?android:attr/listDivider" + android:layout_marginBottom="5dip"/> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_encryptionAlgorithm" + android:text="@string/label_encryptionAlgorithm" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Spinner + android:id="@+id/encryptionAlgorithm" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_hashAlgorithm" + android:text="@string/label_hashAlgorithm" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Spinner + android:id="@+id/hashAlgorithm" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_messageCompression" + android:text="@string/label_messageCompression" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Spinner + android:id="@+id/messageCompression" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_fileCompression" + android:text="@string/label_fileCompression" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_gravity="center_vertical" + android:paddingRight="10dip"/> + + <Spinner + android:id="@+id/fileCompression" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/label_asciiArmour" + android:text="@string/label_asciiArmour" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_gravity="center_vertical" + android:paddingRight="10dip" + android:layout_height="wrap_content" + android:layout_width="0dip" + android:layout_weight="1"/> + + <CheckBox + android:id="@+id/asciiArmour" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + </LinearLayout> + +</ScrollView> diff --git a/res/layout/select_public_key.xml b/res/layout/select_public_key.xml index 9a2d9f578..3c7c6534a 100644 --- a/res/layout/select_public_key.xml +++ b/res/layout/select_public_key.xml @@ -21,34 +21,33 @@ android:layout_height="fill_parent" android:fillViewport="true"> -<ListView - android:id="@+id/list" - android:choiceMode="multipleChoice" - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1"> -</ListView> - -<LinearLayout - android:orientation="horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - style="@android:style/ButtonBar"> - -<Button - android:text="@android:string/ok" - android:id="@+id/btn_ok" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1"/> - -<Button - android:text="@android:string/cancel" - android:id="@+id/btn_cancel" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1"/> - -</LinearLayout> + <ListView + android:id="@+id/list" + android:choiceMode="multipleChoice" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1"/> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + style="@android:style/ButtonBar"> + + <Button + android:text="@android:string/ok" + android:id="@+id/btn_ok" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1"/> + + <Button + android:text="@android:string/cancel" + android:id="@+id/btn_cancel" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1"/> + + </LinearLayout> </LinearLayout> diff --git a/res/layout/select_public_key_item.xml b/res/layout/select_public_key_item.xml index aba0c09b9..bb0dd30a4 100644 --- a/res/layout/select_public_key_item.xml +++ b/res/layout/select_public_key_item.xml @@ -22,75 +22,75 @@ android:layout_height="?android:attr/listPreferredItemHeight" android:layout_width="fill_parent"> -<CheckBox - android:id="@+id/selected" - android:focusable="false" - android:focusableInTouchMode="false" - android:clickable="false" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <CheckBox + android:id="@+id/selected" + android:focusable="false" + android:focusableInTouchMode="false" + android:clickable="false" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -<LinearLayout - android:orientation="vertical" - android:paddingLeft="5dip" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1"> - -<TextView - android:id="@+id/main_user_id" - android:text="Main User ID" - android:textAppearance="?android:attr/textAppearanceLarge" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - -<TextView - android:id="@+id/main_user_id_rest" - android:text="<user@somewhere.com>" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> -</LinearLayout> + <LinearLayout + android:orientation="vertical" + android:paddingLeft="5dip" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1"> -<LinearLayout - android:id="@+id/right_column" - android:orientation="vertical" - android:minWidth="90dip" - android:paddingLeft="3dip" - android:gravity="right" - android:layout_width="wrap_content" - android:layout_height="wrap_content"> - -<TextView - android:id="@+id/key_id" - android:text="BBBBBBBB" - android:textAppearance="?android:attr/textAppearanceMedium" - android:typeface="monospace" - android:layout_width="wrap_content" - android:layout_height="fill_parent"/> - -<TextView - android:id="@+id/creation" - android:textAppearance="?android:attr/textAppearanceSmall" - android:text="31.12.2009" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - -<TextView - android:id="@+id/expiry" - android:textAppearance="?android:attr/textAppearanceSmall" - android:text="31.12.2010" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - -<TextView - android:id="@+id/status" - android:textAppearance="?android:attr/textAppearanceSmall" - android:text="expired" - android:textStyle="italic" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <TextView + android:id="@+id/mainUserId" + android:text="Main User ID" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -</LinearLayout> + <TextView + android:id="@+id/mainUserIdRest" + android:text="<user@somewhere.com>" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + </LinearLayout> + + <LinearLayout + android:orientation="vertical" + android:minWidth="90dip" + android:paddingLeft="3dip" + android:gravity="right" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> -</LinearLayout>
\ No newline at end of file + <TextView + android:id="@+id/keyId" + android:text="BBBBBBBB" + android:textAppearance="?android:attr/textAppearanceSmall" + android:typeface="monospace" + android:layout_width="wrap_content" + android:layout_height="fill_parent"/> + + <TextView + android:id="@+id/creation" + android:textAppearance="?android:attr/textAppearanceSmall" + android:text="31.12.2009" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/expiry" + android:textAppearance="?android:attr/textAppearanceSmall" + android:text="31.12.2010" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/status" + android:textAppearance="?android:attr/textAppearanceSmall" + android:text="expired" + android:textStyle="italic" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + </LinearLayout> + +</LinearLayout> diff --git a/res/layout/select_secret_key.xml b/res/layout/select_secret_key.xml index 64967ace6..f252f56e5 100644 --- a/res/layout/select_secret_key.xml +++ b/res/layout/select_secret_key.xml @@ -21,10 +21,9 @@ android:layout_height="fill_parent" android:fillViewport="true"> -<ListView - android:id="@+id/list" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> -</ListView> + <ListView + android:id="@+id/list" + android:layout_width="fill_parent" + android:layout_height="fill_parent"/> </LinearLayout> diff --git a/res/layout/select_secret_key_item.xml b/res/layout/select_secret_key_item.xml index 0b0475c37..35bf58e23 100644 --- a/res/layout/select_secret_key_item.xml +++ b/res/layout/select_secret_key_item.xml @@ -22,67 +22,68 @@ android:layout_height="?android:attr/listPreferredItemHeight" android:layout_width="fill_parent"> -<LinearLayout - android:orientation="vertical" - android:paddingLeft="5dip" - android:paddingRight="5dip" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1"> + <LinearLayout + android:orientation="vertical" + android:paddingLeft="5dip" + android:paddingRight="5dip" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1"> -<TextView - android:id="@+id/main_user_id" - android:text="Main User ID" - android:textAppearance="?android:attr/textAppearanceLarge" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <TextView + android:id="@+id/mainUserId" + android:text="Main User ID" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -<TextView - android:id="@+id/main_user_id_rest" - android:text="<user@somewhere.com>" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> -</LinearLayout> + <TextView + android:id="@+id/mainUserIdRest" + android:text="<user@somewhere.com>" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -<LinearLayout - android:orientation="vertical" - android:minWidth="90dip" - android:paddingLeft="3dip" - android:gravity="right" - android:layout_width="wrap_content" - android:layout_height="wrap_content"> + </LinearLayout> -<TextView - android:id="@+id/key_id" - android:text="BBBBBBBB" - android:textAppearance="?android:attr/textAppearanceMedium" - android:typeface="monospace" - android:layout_width="wrap_content" - android:layout_height="fill_parent"/> + <LinearLayout + android:orientation="vertical" + android:minWidth="90dip" + android:paddingLeft="3dip" + android:gravity="right" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> -<TextView - android:id="@+id/creation" - android:textAppearance="?android:attr/textAppearanceSmall" - android:text="31.12.2009" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <TextView + android:id="@+id/keyId" + android:text="BBBBBBBB" + android:textAppearance="?android:attr/textAppearanceSmall" + android:typeface="monospace" + android:layout_width="wrap_content" + android:layout_height="fill_parent"/> -<TextView - android:id="@+id/expiry" - android:textAppearance="?android:attr/textAppearanceSmall" - android:text="31.12.2010" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <TextView + android:id="@+id/creation" + android:textAppearance="?android:attr/textAppearanceSmall" + android:text="31.12.2009" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -<TextView - android:id="@+id/status" - android:textAppearance="?android:attr/textAppearanceSmall" - android:text="expired" - android:textStyle="italic" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + <TextView + android:id="@+id/expiry" + android:textAppearance="?android:attr/textAppearanceSmall" + android:text="31.12.2010" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> -</LinearLayout> + <TextView + android:id="@+id/status" + android:textAppearance="?android:attr/textAppearanceSmall" + android:text="expired" + android:textStyle="italic" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + </LinearLayout> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml new file mode 100644 index 000000000..5bb4dc2ba --- /dev/null +++ b/res/values-de/strings.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_name">APG</string> + + <!-- title_lowerCase: capitalized words, no punctuation --> + <string name="title_mailInbox">Mail Inbox</string> + <string name="title_managePublicKeys">Manage Public Keys</string> + <string name="title_manageSecretKeys">Manage Secret Keys</string> + <string name="title_selectRecipients">Select Recipients</string> + <string name="title_selectSignature">Select Signature</string> + <string name="title_encrypt">Encrypt</string> + <string name="title_decrypt">Decrypt</string> + <string name="title_authentification">Authentification</string> + <string name="title_createKey">Create Key</string> + <string name="title_editKey">Edit Key</string> + <string name="title_preferences">Preferences</string> + <string name="title_changePassPhrase">Change Pass Phrase</string> + <string name="title_setPassPhrase">Set Pass Phrase</string> + <string name="title_sendEmail">"Send Mail..."</string> + <string name="title_encryptToFile">Encrypt To File</string> + <string name="title_decryptToFile">Decrypt To File</string> + <string name="title_addAccount">Add Account</string> + <string name="title_importKeys">Import Keys</string> + <string name="title_exportKey">Export Key</string> + <string name="title_exportKeys">Export Keys</string> + + <!-- section_lowerCase: capitalized words, no punctuation --> + <string name="section_userIds">User IDs</string> + <string name="section_keys">Keys</string> + <string name="section_defaults">Defaults</string> + + <!-- btn_lowerCase: capitalized words, no punctuation --> + <string name="btn_encryptToClipboard">Encrypt To Clipboard</string> + <string name="btn_send">Encrypt And Email</string> + <string name="btn_encrypt">Encrypt</string> + <string name="btn_decrypt">Decrypt</string> + <string name="btn_verify">Verify</string> + <string name="btn_selectEncryptKeys">Select Recipients</string> + <string name="btn_reply">Reply</string> + <string name="btn_encryptMessage">Encrypt Message</string> + <string name="btn_decryptMessage">Decrypt Message</string> + <string name="btn_encryptFile">Encrypt File</string> + <string name="btn_decryptFile">Decrypt File</string> + <string name="btn_save">Save</string> + <string name="btn_doNotSave">Cancel</string> + <string name="btn_delete">Delete</string> + <string name="btn_noDate">None</string> + + <!-- menu_lowerCase: capitalized words, no punctuation --> + <string name="menu_about">About</string> + <string name="menu_addAccount">Add GMail Account</string> + <string name="menu_deleteAccount">Delete Account</string> + <string name="menu_managePublicKeys">Manage Public Keys</string> + <string name="menu_manageSecretKeys">Manage Secret Keys</string> + <string name="menu_preferences">Settings</string> + <string name="menu_changePassPhrase">Change Pass Phrase</string> + <string name="menu_setPassPhrase">Set Pass Phrase</string> + <string name="menu_importKeys">Import Keys</string> + <string name="menu_exportKeys">Export Keys</string> + <string name="menu_exportKey">Export Key</string> + <string name="menu_deleteKey">Delete Key</string> + <string name="menu_createKey">Create Key</string> + <string name="menu_editKey">Edit Key</string> + + <!-- label_lowerCase: capitalized words, no punctuation --> + <string name="label_sign">Sign</string> + <string name="label_message">Message</string> + <string name="label_file">File</string> + <string name="label_passPhrase">Pass Phrase</string> + <string name="label_passPhraseAgain">Again</string> + <string name="label_algorithm">Algorithm</string> + <string name="label_asciiArmour">ASCII Armour</string> + <string name="label_selectPublicKeys">Public Key(s)</string> + <string name="label_deleteAfterEncryption">Delete After Encryption</string> + <string name="label_deleteAfterDecryption">Delete After Decryption</string> + <string name="label_encryptionAlgorithm">Encryption Algorithm</string> + <string name="label_hashAlgorithm">Hash Algorithm</string> + <string name="label_asymmetric">Public Key</string> + <string name="label_symmetric">Pass Phrase</string> + + <string name="noKeysSelected">Select</string> + <string name="oneKeySelected">1 Selected</string> + <string name="nKeysSelected">Selected</string> + <string name="unknownUserId"><unknown></string> + <string name="none"><none></string> + <string name="noKey"><no key></string> + <string name="noDate">-</string> + <string name="noExpiry"><no expiry></string> + <string name="unknownStatus"></string> + <string name="canEncrypt">can encrypt</string> + <string name="canSign">can sign</string> + <string name="expired">expired</string> + <string name="notValid">not valid</string> + + <!-- choice_lowerCase: capitalized firwst word, no punctuation --> + <string name="choice_signOnly">Sign only</string> + <string name="choice_encryptOnly">Encrypt only</string> + <string name="choice_signAndEncrypt">Sign and Encrypt</string> + + <string name="dsa">DSA</string> + <string name="elgamal">ElGamal</string> + <string name="rsa">RSA</string> + + <string name="filemanager_titleOpen">Open...</string> + <string name="filemanager_titleSave">Save As...</string> + <string name="filemanager_titleEncrypt">Select File To Encrypt...</string> + <string name="filemanager_titleDecrypt">Select File To Decrypt...</string> + <string name="filemanager_btnOpen">Open</string> + <string name="filemanager_btnSave">Save</string> + + <string name="warning">Warning</string> + <string name="error">Error</string> + <string name="warningMessage">Warning: %s</string> + <string name="errorMessage">Error: %s</string> + + <!-- sentences --> + <string name="wrongPassPhrase">Wrong pass phrase.</string> + <string name="usingClipboardContent">Using clipboard content.</string> + <string name="keySaved">Key saved.</string> + <string name="setAPassPhrase">Set a pass phrase via the option menu first.</string> + <string name="oiFilemanagerNotInstalled">OI File Manager not installed.</string> + <string name="passPhrasesDoNotMatch">The pass phrases didn't match.</string> + <string name="passPhraseMustNotBeEmpty">Empty pass phrases are not allowed.</string> + <string name="passPhraseForSymmetricEncryption">Pass phrase for symmetric encryption:</string> + <string name="passPhraseFor">Pass phrase for %s:</string> + <string name="fileDeleteConfirmation">Are you sure you want to delete\n%s?</string> + <string name="fileDeleteSuccessful">Successfully deleted.</string> + <string name="noFileSelected">Select a file first.</string> + <string name="decryptionSuccessful">Successfully decrypted.</string> + <string name="encryptionSuccessful">Successfully encrypted.</string> + <string name="encryptionToClipboardSuccessful">Successfully encrypted to clipboard.</string> + <string name="enterPassPhraseTwice">Enter the pass phrase twice.</string> + <string name="selectEncryptionKey">Select at least one encryption key.</string> + <string name="selectEncryptionOrSignatureKey">Select at least one encryption key or a signature key.</string> + <string name="specifyFileToEncryptTo">Please specify which file to encrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToDecryptTo">Please specify which file to decrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyGoogleMailAccount">Specify the Google Mail account you want to add.</string> + <string name="specifyFileToImportFrom">Please specify which file to import from.</string> + <string name="specifyFileToExportTo">Please specify which file to export to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToExportSecretKeysTo">Please specify which file to export to.\nWARNING! You are about to export SECRET keys.\nWARNING! File will be overwritten if it exists.</string> + <string name="keyDeletionConfirmation">Do you really want to delete the key '%s'?\nYou can't undo this!</string> + <string name="secretKeyDeletionConfirmation">Do you really want to delete the SECRET key '%s'?\nYou can't undo this!</string> + <string name="keysAddedAndUpdated">Succssfully added %s keys and updated %s keys."</string> + <string name="keysAdded">Succssfully added %s keys.</string> + <string name="keysUpdated">Succssfully updated %s keys.</string> + <string name="noKeysAddedOrUpdated">No keys added or updated.</string> + <string name="keyExported">Succssfully exported 1 key.</string> + <string name="keysExported">Succssfully exported %s keys.</string> + <string name="noKeysExported">No keys exported.</string> + <string name="keyCreationElGamalInfo">Note: only subkeys support ElGamal, and for ElGamal the nearest keysize of 1536, 2048, 3072, 4096, or 8192 will be used.</string> + + <!-- error_lowerCase: phrases, no punctuation, all lowercase, + they will be put after "errorMessage", e.g. "Error: file not found" --> + <string name="error_fileDeleteFailed">deleting '%s' failed</string> + <string name="error_fileNotFound">file not found</string> + <string name="error_noSecretKeyFound">no suitable secret key found</string> + <string name="error_noKnownEncryptionFound">no known kind of encryption found</string> + <string name="error_externalStorageNotReady">external storage not ready</string> + <string name="error_accountNotFound">account '%s' not found</string> + <string name="error_addingAccountFailed">adding account '%s' failed</string> + <string name="error_invalidEmail">invalid email '%s'</string> + <string name="error_keySizeMinimum512bit">key size must be at least 512bit</string> + <string name="error_masterKeyMustNotBeElGamal">the master key cannot be an ElGamal key</string> + <string name="error_unknownAlgorithmChoice">unknown algorithm choice</string> + <string name="error_userIdNeedsAName">you need to specify a name</string> + <string name="error_userIdNeedsAnEmailAddress">you need to specify an email address</string> + <string name="error_keyNeedsAUserId">need at least one user id</string> + <string name="error_mainUserIdMustNotBeEmpty">main user id must not be empty</string> + <string name="error_keyNeedsMasterKey">need at least a master key</string> + <string name="error_expiryMustComeAfterCreation">expiry date must come after creation date</string> + <string name="error_noEncryptionKeysOrPassPhrase">no encryption key(s) or pass phrase given</string> + <string name="error_signatureFailed">signature failed</string> + <string name="error_noSignaturePassPhrase">no pass phrase given</string> + <string name="error_noSignatureKey">no signature key given</string> + <string name="error_invalidData">not valid encryption data</string> + <string name="error_corruptData">corrupt data</string> + <string name="error_noSymmetricEncryptionPacket">couldn't find a packet with symmetric encryption</string> + <string name="error_wrongPassPhrase">wrong pass phrase</string> + <string name="error_savingKeys">error saving some key(s)</string> + + <!-- progress_lowerCase: lowercase, phrases, usually ending in '...' --> + <string name="progress_done">done.</string> + <string name="progress_initializing">initializing...</string> + <string name="progress_saving">saving...</string> + <string name="progress_importing">importing...</string> + <string name="progress_exporting">exporting...</string> + <string name="progress_generating">generating key, this can take a while...</string> + <string name="progress_buildingKey">building key...</string> + <string name="progress_preparingMasterKey">preparing master key...</string> + <string name="progress_certifyingMasterKey">certifying master key...</string> + <string name="progress_buildingMasterKeyRing">building master key ring...</string> + <string name="progress_addingSubKeys">adding sub keys...</string> + <string name="progress_savingKeyRing">saving key ring...</string> + <string name="progress_importingSecretKeys">importing secret keys...</string> + <string name="progress_importingPublicKeys">importing public keys...</string> + <string name="progress_reloadingKeys">reloading keys...</string> + <string name="progress_exportingKey">exporting key...</string> + <string name="progress_exportingKeys">exporting keys...</string> + <string name="progress_extractingSignatureKey">extracting signature key...</string> + <string name="progress_extractingKey">extracting key...</string> + <string name="progress_preparingStreams">preparing streams...</string> + <string name="progress_encrypting">encrypting data...</string> + <string name="progress_decrypting">decrypting data...</string> + <string name="progress_preparingSignature">preparing signature...</string> + <string name="progress_generatingSignature">generating signature...</string> + <string name="progress_processingSignature">processing signature...</string> + <string name="progress_verifyingSignature">verifying signature...</string> + <string name="progress_signing">signing...</string> + <string name="progress_readingData">reading data...</string> + <string name="progress_findingKey">finding key...</string> + <string name="progress_decompressingData">decompressing data...</string> + <string name="progress_verifyingIntegrity">verifying integrity...</string> + +</resources> + diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml new file mode 100644 index 000000000..5bb4dc2ba --- /dev/null +++ b/res/values-ko/strings.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_name">APG</string> + + <!-- title_lowerCase: capitalized words, no punctuation --> + <string name="title_mailInbox">Mail Inbox</string> + <string name="title_managePublicKeys">Manage Public Keys</string> + <string name="title_manageSecretKeys">Manage Secret Keys</string> + <string name="title_selectRecipients">Select Recipients</string> + <string name="title_selectSignature">Select Signature</string> + <string name="title_encrypt">Encrypt</string> + <string name="title_decrypt">Decrypt</string> + <string name="title_authentification">Authentification</string> + <string name="title_createKey">Create Key</string> + <string name="title_editKey">Edit Key</string> + <string name="title_preferences">Preferences</string> + <string name="title_changePassPhrase">Change Pass Phrase</string> + <string name="title_setPassPhrase">Set Pass Phrase</string> + <string name="title_sendEmail">"Send Mail..."</string> + <string name="title_encryptToFile">Encrypt To File</string> + <string name="title_decryptToFile">Decrypt To File</string> + <string name="title_addAccount">Add Account</string> + <string name="title_importKeys">Import Keys</string> + <string name="title_exportKey">Export Key</string> + <string name="title_exportKeys">Export Keys</string> + + <!-- section_lowerCase: capitalized words, no punctuation --> + <string name="section_userIds">User IDs</string> + <string name="section_keys">Keys</string> + <string name="section_defaults">Defaults</string> + + <!-- btn_lowerCase: capitalized words, no punctuation --> + <string name="btn_encryptToClipboard">Encrypt To Clipboard</string> + <string name="btn_send">Encrypt And Email</string> + <string name="btn_encrypt">Encrypt</string> + <string name="btn_decrypt">Decrypt</string> + <string name="btn_verify">Verify</string> + <string name="btn_selectEncryptKeys">Select Recipients</string> + <string name="btn_reply">Reply</string> + <string name="btn_encryptMessage">Encrypt Message</string> + <string name="btn_decryptMessage">Decrypt Message</string> + <string name="btn_encryptFile">Encrypt File</string> + <string name="btn_decryptFile">Decrypt File</string> + <string name="btn_save">Save</string> + <string name="btn_doNotSave">Cancel</string> + <string name="btn_delete">Delete</string> + <string name="btn_noDate">None</string> + + <!-- menu_lowerCase: capitalized words, no punctuation --> + <string name="menu_about">About</string> + <string name="menu_addAccount">Add GMail Account</string> + <string name="menu_deleteAccount">Delete Account</string> + <string name="menu_managePublicKeys">Manage Public Keys</string> + <string name="menu_manageSecretKeys">Manage Secret Keys</string> + <string name="menu_preferences">Settings</string> + <string name="menu_changePassPhrase">Change Pass Phrase</string> + <string name="menu_setPassPhrase">Set Pass Phrase</string> + <string name="menu_importKeys">Import Keys</string> + <string name="menu_exportKeys">Export Keys</string> + <string name="menu_exportKey">Export Key</string> + <string name="menu_deleteKey">Delete Key</string> + <string name="menu_createKey">Create Key</string> + <string name="menu_editKey">Edit Key</string> + + <!-- label_lowerCase: capitalized words, no punctuation --> + <string name="label_sign">Sign</string> + <string name="label_message">Message</string> + <string name="label_file">File</string> + <string name="label_passPhrase">Pass Phrase</string> + <string name="label_passPhraseAgain">Again</string> + <string name="label_algorithm">Algorithm</string> + <string name="label_asciiArmour">ASCII Armour</string> + <string name="label_selectPublicKeys">Public Key(s)</string> + <string name="label_deleteAfterEncryption">Delete After Encryption</string> + <string name="label_deleteAfterDecryption">Delete After Decryption</string> + <string name="label_encryptionAlgorithm">Encryption Algorithm</string> + <string name="label_hashAlgorithm">Hash Algorithm</string> + <string name="label_asymmetric">Public Key</string> + <string name="label_symmetric">Pass Phrase</string> + + <string name="noKeysSelected">Select</string> + <string name="oneKeySelected">1 Selected</string> + <string name="nKeysSelected">Selected</string> + <string name="unknownUserId"><unknown></string> + <string name="none"><none></string> + <string name="noKey"><no key></string> + <string name="noDate">-</string> + <string name="noExpiry"><no expiry></string> + <string name="unknownStatus"></string> + <string name="canEncrypt">can encrypt</string> + <string name="canSign">can sign</string> + <string name="expired">expired</string> + <string name="notValid">not valid</string> + + <!-- choice_lowerCase: capitalized firwst word, no punctuation --> + <string name="choice_signOnly">Sign only</string> + <string name="choice_encryptOnly">Encrypt only</string> + <string name="choice_signAndEncrypt">Sign and Encrypt</string> + + <string name="dsa">DSA</string> + <string name="elgamal">ElGamal</string> + <string name="rsa">RSA</string> + + <string name="filemanager_titleOpen">Open...</string> + <string name="filemanager_titleSave">Save As...</string> + <string name="filemanager_titleEncrypt">Select File To Encrypt...</string> + <string name="filemanager_titleDecrypt">Select File To Decrypt...</string> + <string name="filemanager_btnOpen">Open</string> + <string name="filemanager_btnSave">Save</string> + + <string name="warning">Warning</string> + <string name="error">Error</string> + <string name="warningMessage">Warning: %s</string> + <string name="errorMessage">Error: %s</string> + + <!-- sentences --> + <string name="wrongPassPhrase">Wrong pass phrase.</string> + <string name="usingClipboardContent">Using clipboard content.</string> + <string name="keySaved">Key saved.</string> + <string name="setAPassPhrase">Set a pass phrase via the option menu first.</string> + <string name="oiFilemanagerNotInstalled">OI File Manager not installed.</string> + <string name="passPhrasesDoNotMatch">The pass phrases didn't match.</string> + <string name="passPhraseMustNotBeEmpty">Empty pass phrases are not allowed.</string> + <string name="passPhraseForSymmetricEncryption">Pass phrase for symmetric encryption:</string> + <string name="passPhraseFor">Pass phrase for %s:</string> + <string name="fileDeleteConfirmation">Are you sure you want to delete\n%s?</string> + <string name="fileDeleteSuccessful">Successfully deleted.</string> + <string name="noFileSelected">Select a file first.</string> + <string name="decryptionSuccessful">Successfully decrypted.</string> + <string name="encryptionSuccessful">Successfully encrypted.</string> + <string name="encryptionToClipboardSuccessful">Successfully encrypted to clipboard.</string> + <string name="enterPassPhraseTwice">Enter the pass phrase twice.</string> + <string name="selectEncryptionKey">Select at least one encryption key.</string> + <string name="selectEncryptionOrSignatureKey">Select at least one encryption key or a signature key.</string> + <string name="specifyFileToEncryptTo">Please specify which file to encrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToDecryptTo">Please specify which file to decrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyGoogleMailAccount">Specify the Google Mail account you want to add.</string> + <string name="specifyFileToImportFrom">Please specify which file to import from.</string> + <string name="specifyFileToExportTo">Please specify which file to export to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToExportSecretKeysTo">Please specify which file to export to.\nWARNING! You are about to export SECRET keys.\nWARNING! File will be overwritten if it exists.</string> + <string name="keyDeletionConfirmation">Do you really want to delete the key '%s'?\nYou can't undo this!</string> + <string name="secretKeyDeletionConfirmation">Do you really want to delete the SECRET key '%s'?\nYou can't undo this!</string> + <string name="keysAddedAndUpdated">Succssfully added %s keys and updated %s keys."</string> + <string name="keysAdded">Succssfully added %s keys.</string> + <string name="keysUpdated">Succssfully updated %s keys.</string> + <string name="noKeysAddedOrUpdated">No keys added or updated.</string> + <string name="keyExported">Succssfully exported 1 key.</string> + <string name="keysExported">Succssfully exported %s keys.</string> + <string name="noKeysExported">No keys exported.</string> + <string name="keyCreationElGamalInfo">Note: only subkeys support ElGamal, and for ElGamal the nearest keysize of 1536, 2048, 3072, 4096, or 8192 will be used.</string> + + <!-- error_lowerCase: phrases, no punctuation, all lowercase, + they will be put after "errorMessage", e.g. "Error: file not found" --> + <string name="error_fileDeleteFailed">deleting '%s' failed</string> + <string name="error_fileNotFound">file not found</string> + <string name="error_noSecretKeyFound">no suitable secret key found</string> + <string name="error_noKnownEncryptionFound">no known kind of encryption found</string> + <string name="error_externalStorageNotReady">external storage not ready</string> + <string name="error_accountNotFound">account '%s' not found</string> + <string name="error_addingAccountFailed">adding account '%s' failed</string> + <string name="error_invalidEmail">invalid email '%s'</string> + <string name="error_keySizeMinimum512bit">key size must be at least 512bit</string> + <string name="error_masterKeyMustNotBeElGamal">the master key cannot be an ElGamal key</string> + <string name="error_unknownAlgorithmChoice">unknown algorithm choice</string> + <string name="error_userIdNeedsAName">you need to specify a name</string> + <string name="error_userIdNeedsAnEmailAddress">you need to specify an email address</string> + <string name="error_keyNeedsAUserId">need at least one user id</string> + <string name="error_mainUserIdMustNotBeEmpty">main user id must not be empty</string> + <string name="error_keyNeedsMasterKey">need at least a master key</string> + <string name="error_expiryMustComeAfterCreation">expiry date must come after creation date</string> + <string name="error_noEncryptionKeysOrPassPhrase">no encryption key(s) or pass phrase given</string> + <string name="error_signatureFailed">signature failed</string> + <string name="error_noSignaturePassPhrase">no pass phrase given</string> + <string name="error_noSignatureKey">no signature key given</string> + <string name="error_invalidData">not valid encryption data</string> + <string name="error_corruptData">corrupt data</string> + <string name="error_noSymmetricEncryptionPacket">couldn't find a packet with symmetric encryption</string> + <string name="error_wrongPassPhrase">wrong pass phrase</string> + <string name="error_savingKeys">error saving some key(s)</string> + + <!-- progress_lowerCase: lowercase, phrases, usually ending in '...' --> + <string name="progress_done">done.</string> + <string name="progress_initializing">initializing...</string> + <string name="progress_saving">saving...</string> + <string name="progress_importing">importing...</string> + <string name="progress_exporting">exporting...</string> + <string name="progress_generating">generating key, this can take a while...</string> + <string name="progress_buildingKey">building key...</string> + <string name="progress_preparingMasterKey">preparing master key...</string> + <string name="progress_certifyingMasterKey">certifying master key...</string> + <string name="progress_buildingMasterKeyRing">building master key ring...</string> + <string name="progress_addingSubKeys">adding sub keys...</string> + <string name="progress_savingKeyRing">saving key ring...</string> + <string name="progress_importingSecretKeys">importing secret keys...</string> + <string name="progress_importingPublicKeys">importing public keys...</string> + <string name="progress_reloadingKeys">reloading keys...</string> + <string name="progress_exportingKey">exporting key...</string> + <string name="progress_exportingKeys">exporting keys...</string> + <string name="progress_extractingSignatureKey">extracting signature key...</string> + <string name="progress_extractingKey">extracting key...</string> + <string name="progress_preparingStreams">preparing streams...</string> + <string name="progress_encrypting">encrypting data...</string> + <string name="progress_decrypting">decrypting data...</string> + <string name="progress_preparingSignature">preparing signature...</string> + <string name="progress_generatingSignature">generating signature...</string> + <string name="progress_processingSignature">processing signature...</string> + <string name="progress_verifyingSignature">verifying signature...</string> + <string name="progress_signing">signing...</string> + <string name="progress_readingData">reading data...</string> + <string name="progress_findingKey">finding key...</string> + <string name="progress_decompressingData">decompressing data...</string> + <string name="progress_verifyingIntegrity">verifying integrity...</string> + +</resources> + diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml new file mode 100644 index 000000000..5bb4dc2ba --- /dev/null +++ b/res/values-ru/strings.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_name">APG</string> + + <!-- title_lowerCase: capitalized words, no punctuation --> + <string name="title_mailInbox">Mail Inbox</string> + <string name="title_managePublicKeys">Manage Public Keys</string> + <string name="title_manageSecretKeys">Manage Secret Keys</string> + <string name="title_selectRecipients">Select Recipients</string> + <string name="title_selectSignature">Select Signature</string> + <string name="title_encrypt">Encrypt</string> + <string name="title_decrypt">Decrypt</string> + <string name="title_authentification">Authentification</string> + <string name="title_createKey">Create Key</string> + <string name="title_editKey">Edit Key</string> + <string name="title_preferences">Preferences</string> + <string name="title_changePassPhrase">Change Pass Phrase</string> + <string name="title_setPassPhrase">Set Pass Phrase</string> + <string name="title_sendEmail">"Send Mail..."</string> + <string name="title_encryptToFile">Encrypt To File</string> + <string name="title_decryptToFile">Decrypt To File</string> + <string name="title_addAccount">Add Account</string> + <string name="title_importKeys">Import Keys</string> + <string name="title_exportKey">Export Key</string> + <string name="title_exportKeys">Export Keys</string> + + <!-- section_lowerCase: capitalized words, no punctuation --> + <string name="section_userIds">User IDs</string> + <string name="section_keys">Keys</string> + <string name="section_defaults">Defaults</string> + + <!-- btn_lowerCase: capitalized words, no punctuation --> + <string name="btn_encryptToClipboard">Encrypt To Clipboard</string> + <string name="btn_send">Encrypt And Email</string> + <string name="btn_encrypt">Encrypt</string> + <string name="btn_decrypt">Decrypt</string> + <string name="btn_verify">Verify</string> + <string name="btn_selectEncryptKeys">Select Recipients</string> + <string name="btn_reply">Reply</string> + <string name="btn_encryptMessage">Encrypt Message</string> + <string name="btn_decryptMessage">Decrypt Message</string> + <string name="btn_encryptFile">Encrypt File</string> + <string name="btn_decryptFile">Decrypt File</string> + <string name="btn_save">Save</string> + <string name="btn_doNotSave">Cancel</string> + <string name="btn_delete">Delete</string> + <string name="btn_noDate">None</string> + + <!-- menu_lowerCase: capitalized words, no punctuation --> + <string name="menu_about">About</string> + <string name="menu_addAccount">Add GMail Account</string> + <string name="menu_deleteAccount">Delete Account</string> + <string name="menu_managePublicKeys">Manage Public Keys</string> + <string name="menu_manageSecretKeys">Manage Secret Keys</string> + <string name="menu_preferences">Settings</string> + <string name="menu_changePassPhrase">Change Pass Phrase</string> + <string name="menu_setPassPhrase">Set Pass Phrase</string> + <string name="menu_importKeys">Import Keys</string> + <string name="menu_exportKeys">Export Keys</string> + <string name="menu_exportKey">Export Key</string> + <string name="menu_deleteKey">Delete Key</string> + <string name="menu_createKey">Create Key</string> + <string name="menu_editKey">Edit Key</string> + + <!-- label_lowerCase: capitalized words, no punctuation --> + <string name="label_sign">Sign</string> + <string name="label_message">Message</string> + <string name="label_file">File</string> + <string name="label_passPhrase">Pass Phrase</string> + <string name="label_passPhraseAgain">Again</string> + <string name="label_algorithm">Algorithm</string> + <string name="label_asciiArmour">ASCII Armour</string> + <string name="label_selectPublicKeys">Public Key(s)</string> + <string name="label_deleteAfterEncryption">Delete After Encryption</string> + <string name="label_deleteAfterDecryption">Delete After Decryption</string> + <string name="label_encryptionAlgorithm">Encryption Algorithm</string> + <string name="label_hashAlgorithm">Hash Algorithm</string> + <string name="label_asymmetric">Public Key</string> + <string name="label_symmetric">Pass Phrase</string> + + <string name="noKeysSelected">Select</string> + <string name="oneKeySelected">1 Selected</string> + <string name="nKeysSelected">Selected</string> + <string name="unknownUserId"><unknown></string> + <string name="none"><none></string> + <string name="noKey"><no key></string> + <string name="noDate">-</string> + <string name="noExpiry"><no expiry></string> + <string name="unknownStatus"></string> + <string name="canEncrypt">can encrypt</string> + <string name="canSign">can sign</string> + <string name="expired">expired</string> + <string name="notValid">not valid</string> + + <!-- choice_lowerCase: capitalized firwst word, no punctuation --> + <string name="choice_signOnly">Sign only</string> + <string name="choice_encryptOnly">Encrypt only</string> + <string name="choice_signAndEncrypt">Sign and Encrypt</string> + + <string name="dsa">DSA</string> + <string name="elgamal">ElGamal</string> + <string name="rsa">RSA</string> + + <string name="filemanager_titleOpen">Open...</string> + <string name="filemanager_titleSave">Save As...</string> + <string name="filemanager_titleEncrypt">Select File To Encrypt...</string> + <string name="filemanager_titleDecrypt">Select File To Decrypt...</string> + <string name="filemanager_btnOpen">Open</string> + <string name="filemanager_btnSave">Save</string> + + <string name="warning">Warning</string> + <string name="error">Error</string> + <string name="warningMessage">Warning: %s</string> + <string name="errorMessage">Error: %s</string> + + <!-- sentences --> + <string name="wrongPassPhrase">Wrong pass phrase.</string> + <string name="usingClipboardContent">Using clipboard content.</string> + <string name="keySaved">Key saved.</string> + <string name="setAPassPhrase">Set a pass phrase via the option menu first.</string> + <string name="oiFilemanagerNotInstalled">OI File Manager not installed.</string> + <string name="passPhrasesDoNotMatch">The pass phrases didn't match.</string> + <string name="passPhraseMustNotBeEmpty">Empty pass phrases are not allowed.</string> + <string name="passPhraseForSymmetricEncryption">Pass phrase for symmetric encryption:</string> + <string name="passPhraseFor">Pass phrase for %s:</string> + <string name="fileDeleteConfirmation">Are you sure you want to delete\n%s?</string> + <string name="fileDeleteSuccessful">Successfully deleted.</string> + <string name="noFileSelected">Select a file first.</string> + <string name="decryptionSuccessful">Successfully decrypted.</string> + <string name="encryptionSuccessful">Successfully encrypted.</string> + <string name="encryptionToClipboardSuccessful">Successfully encrypted to clipboard.</string> + <string name="enterPassPhraseTwice">Enter the pass phrase twice.</string> + <string name="selectEncryptionKey">Select at least one encryption key.</string> + <string name="selectEncryptionOrSignatureKey">Select at least one encryption key or a signature key.</string> + <string name="specifyFileToEncryptTo">Please specify which file to encrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToDecryptTo">Please specify which file to decrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyGoogleMailAccount">Specify the Google Mail account you want to add.</string> + <string name="specifyFileToImportFrom">Please specify which file to import from.</string> + <string name="specifyFileToExportTo">Please specify which file to export to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToExportSecretKeysTo">Please specify which file to export to.\nWARNING! You are about to export SECRET keys.\nWARNING! File will be overwritten if it exists.</string> + <string name="keyDeletionConfirmation">Do you really want to delete the key '%s'?\nYou can't undo this!</string> + <string name="secretKeyDeletionConfirmation">Do you really want to delete the SECRET key '%s'?\nYou can't undo this!</string> + <string name="keysAddedAndUpdated">Succssfully added %s keys and updated %s keys."</string> + <string name="keysAdded">Succssfully added %s keys.</string> + <string name="keysUpdated">Succssfully updated %s keys.</string> + <string name="noKeysAddedOrUpdated">No keys added or updated.</string> + <string name="keyExported">Succssfully exported 1 key.</string> + <string name="keysExported">Succssfully exported %s keys.</string> + <string name="noKeysExported">No keys exported.</string> + <string name="keyCreationElGamalInfo">Note: only subkeys support ElGamal, and for ElGamal the nearest keysize of 1536, 2048, 3072, 4096, or 8192 will be used.</string> + + <!-- error_lowerCase: phrases, no punctuation, all lowercase, + they will be put after "errorMessage", e.g. "Error: file not found" --> + <string name="error_fileDeleteFailed">deleting '%s' failed</string> + <string name="error_fileNotFound">file not found</string> + <string name="error_noSecretKeyFound">no suitable secret key found</string> + <string name="error_noKnownEncryptionFound">no known kind of encryption found</string> + <string name="error_externalStorageNotReady">external storage not ready</string> + <string name="error_accountNotFound">account '%s' not found</string> + <string name="error_addingAccountFailed">adding account '%s' failed</string> + <string name="error_invalidEmail">invalid email '%s'</string> + <string name="error_keySizeMinimum512bit">key size must be at least 512bit</string> + <string name="error_masterKeyMustNotBeElGamal">the master key cannot be an ElGamal key</string> + <string name="error_unknownAlgorithmChoice">unknown algorithm choice</string> + <string name="error_userIdNeedsAName">you need to specify a name</string> + <string name="error_userIdNeedsAnEmailAddress">you need to specify an email address</string> + <string name="error_keyNeedsAUserId">need at least one user id</string> + <string name="error_mainUserIdMustNotBeEmpty">main user id must not be empty</string> + <string name="error_keyNeedsMasterKey">need at least a master key</string> + <string name="error_expiryMustComeAfterCreation">expiry date must come after creation date</string> + <string name="error_noEncryptionKeysOrPassPhrase">no encryption key(s) or pass phrase given</string> + <string name="error_signatureFailed">signature failed</string> + <string name="error_noSignaturePassPhrase">no pass phrase given</string> + <string name="error_noSignatureKey">no signature key given</string> + <string name="error_invalidData">not valid encryption data</string> + <string name="error_corruptData">corrupt data</string> + <string name="error_noSymmetricEncryptionPacket">couldn't find a packet with symmetric encryption</string> + <string name="error_wrongPassPhrase">wrong pass phrase</string> + <string name="error_savingKeys">error saving some key(s)</string> + + <!-- progress_lowerCase: lowercase, phrases, usually ending in '...' --> + <string name="progress_done">done.</string> + <string name="progress_initializing">initializing...</string> + <string name="progress_saving">saving...</string> + <string name="progress_importing">importing...</string> + <string name="progress_exporting">exporting...</string> + <string name="progress_generating">generating key, this can take a while...</string> + <string name="progress_buildingKey">building key...</string> + <string name="progress_preparingMasterKey">preparing master key...</string> + <string name="progress_certifyingMasterKey">certifying master key...</string> + <string name="progress_buildingMasterKeyRing">building master key ring...</string> + <string name="progress_addingSubKeys">adding sub keys...</string> + <string name="progress_savingKeyRing">saving key ring...</string> + <string name="progress_importingSecretKeys">importing secret keys...</string> + <string name="progress_importingPublicKeys">importing public keys...</string> + <string name="progress_reloadingKeys">reloading keys...</string> + <string name="progress_exportingKey">exporting key...</string> + <string name="progress_exportingKeys">exporting keys...</string> + <string name="progress_extractingSignatureKey">extracting signature key...</string> + <string name="progress_extractingKey">extracting key...</string> + <string name="progress_preparingStreams">preparing streams...</string> + <string name="progress_encrypting">encrypting data...</string> + <string name="progress_decrypting">decrypting data...</string> + <string name="progress_preparingSignature">preparing signature...</string> + <string name="progress_generatingSignature">generating signature...</string> + <string name="progress_processingSignature">processing signature...</string> + <string name="progress_verifyingSignature">verifying signature...</string> + <string name="progress_signing">signing...</string> + <string name="progress_readingData">reading data...</string> + <string name="progress_findingKey">finding key...</string> + <string name="progress_decompressingData">decompressing data...</string> + <string name="progress_verifyingIntegrity">verifying integrity...</string> + +</resources> + diff --git a/res/values/strings.xml b/res/values/strings.xml index b1fa76915..856ed0c4e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -16,53 +16,226 @@ <resources> <string name="app_name">APG</string> + + <!-- title_lowerCase: capitalized words, no punctuation --> <string name="title_mailInbox">Mail Inbox</string> <string name="title_managePublicKeys">Manage Public Keys</string> <string name="title_manageSecretKeys">Manage Secret Keys</string> <string name="title_selectRecipients">Select Recipients</string> <string name="title_selectSignature">Select Signature</string> - <string name="title_encryptMessage">Encrypt Message</string> - <string name="title_decryptMessage">Decrypt Message</string> + <string name="title_encrypt">Encrypt</string> + <string name="title_decrypt">Decrypt</string> <string name="title_authentification">Authentification</string> <string name="title_createKey">Create Key</string> <string name="title_editKey">Edit Key</string> + <string name="title_preferences">Preferences</string> + <string name="title_changePassPhrase">Change Pass Phrase</string> + <string name="title_setPassPhrase">Set Pass Phrase</string> + <string name="title_sendEmail">"Send Mail..."</string> + <string name="title_encryptToFile">Encrypt To File</string> + <string name="title_decryptToFile">Decrypt To File</string> + <string name="title_addAccount">Add Account</string> + <string name="title_importKeys">Import Keys</string> + <string name="title_exportKey">Export Key</string> + <string name="title_exportKeys">Export Keys</string> + <!-- section_lowerCase: capitalized words, no punctuation --> <string name="section_userIds">User IDs</string> <string name="section_keys">Keys</string> + <string name="section_general">General</string> + <string name="section_defaults">Defaults</string> - <string name="btn_send">Send via Email</string> + <!-- btn_lowerCase: capitalized words, no punctuation --> + <string name="btn_encryptToClipboard">Encrypt To Clipboard</string> + <string name="btn_send">Encrypt And Email</string> + <string name="btn_encrypt">Encrypt</string> <string name="btn_decrypt">Decrypt</string> + <string name="btn_verify">Verify</string> <string name="btn_selectEncryptKeys">Select Recipients</string> <string name="btn_reply">Reply</string> <string name="btn_encryptMessage">Encrypt Message</string> <string name="btn_decryptMessage">Decrypt Message</string> + <string name="btn_encryptFile">Encrypt File</string> + <string name="btn_decryptFile">Decrypt File</string> <string name="btn_save">Save</string> <string name="btn_doNotSave">Cancel</string> + <string name="btn_delete">Delete</string> + <string name="btn_noDate">None</string> + <!-- menu_lowerCase: capitalized words, no punctuation --> <string name="menu_about">About</string> <string name="menu_addAccount">Add GMail Account</string> + <string name="menu_deleteAccount">Delete Account</string> <string name="menu_managePublicKeys">Manage Public Keys</string> <string name="menu_manageSecretKeys">Manage Secret Keys</string> + <string name="menu_preferences">Settings</string> + <string name="menu_changePassPhrase">Change Pass Phrase</string> + <string name="menu_setPassPhrase">Set Pass Phrase</string> + <string name="menu_importKeys">Import Keys</string> + <string name="menu_exportKeys">Export Keys</string> + <string name="menu_exportKey">Export Key</string> + <string name="menu_deleteKey">Delete Key</string> + <string name="menu_createKey">Create Key</string> + <string name="menu_editKey">Edit Key</string> + + <!-- label_lowerCase: capitalized words, no punctuation --> + <string name="label_sign">Sign</string> + <string name="label_message">Message</string> + <string name="label_file">File</string> + <string name="label_passPhrase">Pass Phrase</string> + <string name="label_passPhraseAgain">Again</string> + <string name="label_algorithm">Algorithm</string> + <string name="label_asciiArmour">ASCII Armour</string> + <string name="label_selectPublicKeys">Public Key(s)</string> + <string name="label_deleteAfterEncryption">Delete After Encryption</string> + <string name="label_deleteAfterDecryption">Delete After Decryption</string> + <string name="label_encryptionAlgorithm">Encryption Algorithm</string> + <string name="label_hashAlgorithm">Hash Algorithm</string> + <string name="label_asymmetric">Public Key</string> + <string name="label_symmetric">Pass Phrase</string> + <string name="label_passPhraseCacheTtl">Pass Phrase Cache</string> + <string name="label_messageCompression">Message Compression</string> + <string name="label_fileCompression">File Compression</string> - <string name="sign">Sign</string> - <string name="sign_as">Sign as</string> - <string name="no_keys_selected">Select Recipients</string> - <string name="one_key_selected">1 Recipient</string> - <string name="n_keys_selected">Recipients</string> - <string name="unknown_user_id"><unknown></string> + <string name="noKeysSelected">Select</string> + <string name="oneKeySelected">1 Selected</string> + <string name="nKeysSelected">Selected</string> + <string name="unknownUserId"><unknown></string> <string name="none"><none></string> + <string name="noKey"><no key></string> + <string name="noDate">-</string> + <string name="noExpiry"><no expiry></string> + <string name="unknownStatus"></string> + <string name="canEncrypt">can encrypt</string> + <string name="canSign">can sign</string> + <string name="expired">expired</string> + <string name="notValid">not valid</string> - <string name="sign_only">Sign only</string> - <string name="encrypt_only">Encrypt only</string> - <string name="sign_and_encrypt">Sign and Encrypt</string> + <!-- choice_lowerCase: capitalized firwst word, no punctuation --> + <string name="choice_none">None</string> + <string name="choice_signOnly">Sign only</string> + <string name="choice_encryptOnly">Encrypt only</string> + <string name="choice_signAndEncrypt">Sign and Encrypt</string> + <string name="choice_15secs">15 secs</string> + <string name="choice_1min">1 min</string> + <string name="choice_3mins">3 mins</string> + <string name="choice_5mins">5 mins</string> + <string name="choice_10mins">10 mins</string> + <string name="choice_untilQuit">until quit</string> <string name="dsa">DSA</string> <string name="elgamal">ElGamal</string> <string name="rsa">RSA</string> - <string name="wrong_pass_phrase">Wrong pass phrase.</string> - <string name="using_clipboard_content">Using clipboard content.</string> - <string name="key_saved">Key saved.</string> - <string name="set_a_pass_phrase">Set a pass phrase via the option menu first.</string> + <string name="filemanager_titleOpen">Open...</string> + <string name="filemanager_titleSave">Save As...</string> + <string name="filemanager_titleEncrypt">Select File To Encrypt...</string> + <string name="filemanager_titleDecrypt">Select File To Decrypt...</string> + <string name="filemanager_btnOpen">Open</string> + <string name="filemanager_btnSave">Save</string> + + <string name="warning">Warning</string> + <string name="error">Error</string> + <string name="warningMessage">Warning: %s</string> + <string name="errorMessage">Error: %s</string> + + <!-- sentences --> + <string name="wrongPassPhrase">Wrong pass phrase.</string> + <string name="usingClipboardContent">Using clipboard content.</string> + <string name="keySaved">Key saved.</string> + <string name="setAPassPhrase">Set a pass phrase via the option menu first.</string> + <string name="oiFilemanagerNotInstalled">OI File Manager not installed.</string> + <string name="passPhrasesDoNotMatch">The pass phrases didn't match.</string> + <string name="passPhraseMustNotBeEmpty">Empty pass phrases are not allowed.</string> + <string name="passPhraseForSymmetricEncryption">Pass phrase for symmetric encryption:</string> + <string name="passPhraseFor">Pass phrase for %s:</string> + <string name="fileDeleteConfirmation">Are you sure you want to delete\n%s?</string> + <string name="fileDeleteSuccessful">Successfully deleted.</string> + <string name="noFileSelected">Select a file first.</string> + <string name="decryptionSuccessful">Successfully decrypted.</string> + <string name="encryptionSuccessful">Successfully encrypted.</string> + <string name="encryptionToClipboardSuccessful">Successfully encrypted to clipboard.</string> + <string name="enterPassPhraseTwice">Enter the pass phrase twice.</string> + <string name="selectEncryptionKey">Select at least one encryption key.</string> + <string name="selectEncryptionOrSignatureKey">Select at least one encryption key or a signature key.</string> + <string name="specifyFileToEncryptTo">Please specify which file to encrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToDecryptTo">Please specify which file to decrypt to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyGoogleMailAccount">Specify the Google Mail account you want to add.</string> + <string name="specifyFileToImportFrom">Please specify which file to import from.</string> + <string name="specifyFileToExportTo">Please specify which file to export to.\nWARNING! File will be overwritten if it exists.</string> + <string name="specifyFileToExportSecretKeysTo">Please specify which file to export to.\nWARNING! You are about to export SECRET keys.\nWARNING! File will be overwritten if it exists.</string> + <string name="keyDeletionConfirmation">Do you really want to delete the key '%s'?\nYou can't undo this!</string> + <string name="secretKeyDeletionConfirmation">Do you really want to delete the SECRET key '%s'?\nYou can't undo this!</string> + <string name="keysAddedAndUpdated">Succssfully added %s keys and updated %s keys."</string> + <string name="keysAdded">Succssfully added %s keys.</string> + <string name="keysUpdated">Succssfully updated %s keys.</string> + <string name="noKeysAddedOrUpdated">No keys added or updated.</string> + <string name="keyExported">Succssfully exported 1 key.</string> + <string name="keysExported">Succssfully exported %s keys.</string> + <string name="noKeysExported">No keys exported.</string> + <string name="keyCreationElGamalInfo">Note: only subkeys support ElGamal, and for ElGamal the nearest keysize of 1536, 2048, 3072, 4096, or 8192 will be used.</string> + + <!-- error_lowerCase: phrases, no punctuation, all lowercase, + they will be put after "errorMessage", e.g. "Error: file not found" --> + <string name="error_fileDeleteFailed">deleting '%s' failed</string> + <string name="error_fileNotFound">file not found</string> + <string name="error_noSecretKeyFound">no suitable secret key found</string> + <string name="error_noKnownEncryptionFound">no known kind of encryption found</string> + <string name="error_externalStorageNotReady">external storage not ready</string> + <string name="error_accountNotFound">account '%s' not found</string> + <string name="error_addingAccountFailed">adding account '%s' failed</string> + <string name="error_invalidEmail">invalid email '%s'</string> + <string name="error_keySizeMinimum512bit">key size must be at least 512bit</string> + <string name="error_masterKeyMustNotBeElGamal">the master key cannot be an ElGamal key</string> + <string name="error_unknownAlgorithmChoice">unknown algorithm choice</string> + <string name="error_userIdNeedsAName">you need to specify a name</string> + <string name="error_userIdNeedsAnEmailAddress">you need to specify an email address</string> + <string name="error_keyNeedsAUserId">need at least one user id</string> + <string name="error_mainUserIdMustNotBeEmpty">main user id must not be empty</string> + <string name="error_keyNeedsMasterKey">need at least a master key</string> + <string name="error_expiryMustComeAfterCreation">expiry date must come after creation date</string> + <string name="error_noEncryptionKeysOrPassPhrase">no encryption key(s) or pass phrase given</string> + <string name="error_signatureFailed">signature failed</string> + <string name="error_noSignaturePassPhrase">no pass phrase given</string> + <string name="error_noSignatureKey">no signature key given</string> + <string name="error_invalidData">not valid encryption data</string> + <string name="error_corruptData">corrupt data</string> + <string name="error_noSymmetricEncryptionPacket">couldn't find a packet with symmetric encryption</string> + <string name="error_wrongPassPhrase">wrong pass phrase</string> + <string name="error_savingKeys">error saving some key(s)</string> + + <!-- progress_lowerCase: lowercase, phrases, usually ending in '...' --> + <string name="progress_done">done.</string> + <string name="progress_initializing">initializing...</string> + <string name="progress_saving">saving...</string> + <string name="progress_importing">importing...</string> + <string name="progress_exporting">exporting...</string> + <string name="progress_generating">generating key, this can take a while...</string> + <string name="progress_buildingKey">building key...</string> + <string name="progress_preparingMasterKey">preparing master key...</string> + <string name="progress_certifyingMasterKey">certifying master key...</string> + <string name="progress_buildingMasterKeyRing">building master key ring...</string> + <string name="progress_addingSubKeys">adding sub keys...</string> + <string name="progress_savingKeyRing">saving key ring...</string> + <string name="progress_importingSecretKeys">importing secret keys...</string> + <string name="progress_importingPublicKeys">importing public keys...</string> + <string name="progress_reloadingKeys">reloading keys...</string> + <string name="progress_exportingKey">exporting key...</string> + <string name="progress_exportingKeys">exporting keys...</string> + <string name="progress_extractingSignatureKey">extracting signature key...</string> + <string name="progress_extractingKey">extracting key...</string> + <string name="progress_preparingStreams">preparing streams...</string> + <string name="progress_encrypting">encrypting data...</string> + <string name="progress_decrypting">decrypting data...</string> + <string name="progress_preparingSignature">preparing signature...</string> + <string name="progress_generatingSignature">generating signature...</string> + <string name="progress_processingSignature">processing signature...</string> + <string name="progress_verifyingSignature">verifying signature...</string> + <string name="progress_signing">signing...</string> + <string name="progress_readingData">reading data...</string> + <string name="progress_findingKey">finding key...</string> + <string name="progress_decompressingData">decompressing data...</string> + <string name="progress_verifyingIntegrity">verifying integrity...</string> + </resources> diff --git a/src/org/openintents/intents/FileManager.java b/src/org/openintents/intents/FileManager.java new file mode 100644 index 000000000..3a5cc0d86 --- /dev/null +++ b/src/org/openintents/intents/FileManager.java @@ -0,0 +1,78 @@ +/*
+ * Copyright (C) 2008 OpenIntents.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openintents.intents;
+
+// Version Dec 9, 2008
+
+/**
+ * Provides OpenIntents actions, extras, and categories used by providers.
+ * <p>
+ * These specifiers extend the standard Android specifiers.
+ * </p>
+ */
+public final class FileManager {
+
+ /**
+ * Activity Action: Pick a file through the file manager, or let user
+ * specify a custom file name. Data is the current file name or file name
+ * suggestion. Returns a new file name as file URI in data.
+ *
+ * <p>
+ * Constant Value: "org.openintents.action.PICK_FILE"
+ * </p>
+ */
+ public static final String ACTION_PICK_FILE = "org.openintents.action.PICK_FILE";
+
+ /**
+ * Activity Action: Pick a directory through the file manager, or let user
+ * specify a custom file name. Data is the current directory name or
+ * directory name suggestion. Returns a new directory name as file URI in
+ * data.
+ *
+ * <p>
+ * Constant Value: "org.openintents.action.PICK_DIRECTORY"
+ * </p>
+ */
+ public static final String ACTION_PICK_DIRECTORY = "org.openintents.action.PICK_DIRECTORY";
+
+ /**
+ * The title to display.
+ *
+ * <p>
+ * This is shown in the title bar of the file manager.
+ * </p>
+ *
+ * <p>
+ * Constant Value: "org.openintents.extra.TITLE"
+ * </p>
+ */
+ public static final String EXTRA_TITLE = "org.openintents.extra.TITLE";
+
+ /**
+ * The text on the button to display.
+ *
+ * <p>
+ * Depending on the use, it makes sense to set this to "Open" or "Save".
+ * </p>
+ *
+ * <p>
+ * Constant Value: "org.openintents.extra.BUTTON_TEXT"
+ * </p>
+ */
+ public static final String EXTRA_BUTTON_TEXT = "org.openintents.extra.BUTTON_TEXT";
+
+}
diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java index 68c4f8877..e290a501e 100644 --- a/src/org/thialfihar/android/apg/Apg.java +++ b/src/org/thialfihar/android/apg/Apg.java @@ -16,7 +16,8 @@ package org.thialfihar.android.apg;
-import java.io.BufferedOutputStream;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -39,9 +40,12 @@ import java.util.Comparator; import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
import java.util.Vector;
import java.util.regex.Pattern;
+import org.bouncycastle2.bcpg.ArmoredInputStream;
import org.bouncycastle2.bcpg.ArmoredOutputStream;
import org.bouncycastle2.bcpg.BCPGOutputStream;
import org.bouncycastle2.bcpg.CompressionAlgorithmTags;
@@ -63,6 +67,7 @@ import org.bouncycastle2.openpgp.PGPLiteralDataGenerator; import org.bouncycastle2.openpgp.PGPObjectFactory;
import org.bouncycastle2.openpgp.PGPOnePassSignature;
import org.bouncycastle2.openpgp.PGPOnePassSignatureList;
+import org.bouncycastle2.openpgp.PGPPBEEncryptedData;
import org.bouncycastle2.openpgp.PGPPrivateKey;
import org.bouncycastle2.openpgp.PGPPublicKey;
import org.bouncycastle2.openpgp.PGPPublicKeyEncryptedData;
@@ -95,9 +100,11 @@ public class Apg { public static class Intent {
public static final String DECRYPT = "org.thialfihar.android.apg.intent.DECRYPT";
public static final String ENCRYPT = "org.thialfihar.android.apg.intent.ENCRYPT";
+ public static final String DECRYPT_FILE = "org.thialfihar.android.apg.intent.DECRYPT_FILE";
+ public static final String ENCRYPT_FILE = "org.thialfihar.android.apg.intent.ENCRYPT_FILE";
}
- public static String VERSION = "0.8.0";
+ public static String VERSION = "0.9.5";
public static String FULL_VERSION = "APG v" + VERSION;
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS =
@@ -118,22 +125,18 @@ public class Apg { CompressionAlgorithmTags.BZIP2,
CompressionAlgorithmTags.ZIP };
- protected static Vector<PGPPublicKeyRing> mPublicKeyRings;
- protected static Vector<PGPSecretKeyRing> mSecretKeyRings;
+ protected static Vector<PGPPublicKeyRing> mPublicKeyRings = new Vector<PGPPublicKeyRing>();
+ protected static Vector<PGPSecretKeyRing> mSecretKeyRings = new Vector<PGPSecretKeyRing>();
public static Pattern PGP_MESSAGE =
- Pattern.compile(".*?(-----BEGIN PGP MESSAGE-----\n.*?-----END PGP MESSAGE-----).*",
+ Pattern.compile(".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*",
Pattern.DOTALL);
- protected static boolean mInitialized = false;
-
- protected static final int RETURN_NO_MASTER_KEY = -2;
- protected static final int RETURN_ERROR = -1;
- protected static final int RETURN_OK = 0;
- protected static final int RETURN_UPDATED = 1;
+ public static Pattern PGP_SIGNED_MESSAGE =
+ Pattern.compile(".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
+ Pattern.DOTALL);
- protected static final int TYPE_PUBLIC = 0;
- protected static final int TYPE_SECRET = 1;
+ protected static boolean mInitialized = false;
protected static HashMap<Long, Integer> mSecretKeyIdToIdMap;
protected static HashMap<Long, PGPSecretKeyRing> mSecretKeyIdToKeyRingMap;
@@ -153,7 +156,9 @@ public class Apg { PublicKeys.KEY_DATA,
PublicKeys.WHO_ID, };
- private static String mPassPhrase = null;
+ private static HashMap<Long, CachedPassPhrase> mPassPhraseCache =
+ new HashMap<Long, CachedPassPhrase>();
+ private static String mEditPassPhrase = null;
public static class GeneralException extends Exception {
static final long serialVersionUID = 0xf812773342L;
@@ -163,6 +168,14 @@ public class Apg { }
}
+ public static class NoAsymmetricEncryptionException extends Exception {
+ static final long serialVersionUID = 0xf812773343L;
+
+ public NoAsymmetricEncryptionException() {
+ super();
+ }
+ }
+
static {
mPublicKeyRings = new Vector<PGPPublicKeyRing>();
mSecretKeyRings = new Vector<PGPSecretKeyRing>();
@@ -173,13 +186,20 @@ public class Apg { }
public static void initialize(Activity context) {
- setPassPhrase(null);
if (mInitialized) {
return;
}
- loadKeyRings(context, TYPE_PUBLIC);
- loadKeyRings(context, TYPE_SECRET);
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ File dir = new File(Constants.path.app_dir);
+ if (!dir.exists() && !dir.mkdirs()) {
+ // ignore this for now, it's not crucial
+ // that the directory doesn't exist at this point
+ }
+ }
+
+ loadKeyRings(context, Id.type.public_key);
+ loadKeyRings(context, Id.type.secret_key);
mInitialized = true;
}
@@ -254,24 +274,63 @@ public class Apg { }
}
- public static void setPassPhrase(String passPhrase) {
- mPassPhrase = passPhrase;
+ public static void setEditPassPhrase(String passPhrase) {
+ mEditPassPhrase = passPhrase;
+ }
+
+ public static String getEditPassPhrase() {
+ return mEditPassPhrase;
}
- public static String getPassPhrase() {
- return mPassPhrase;
+ public static void setCachedPassPhrase(long keyId, String passPhrase) {
+ mPassPhraseCache.put(keyId, new CachedPassPhrase(new Date().getTime(), passPhrase));
}
- public static PGPSecretKey createKey(KeyEditor.AlgorithmChoice algorithmChoice, int keySize,
- String passPhrase)
+ public static String getCachedPassPhrase(long keyId) {
+ long realId = keyId;
+ if (realId != Id.key.symmetric) {
+ PGPSecretKeyRing keyRing = findSecretKeyRing(keyId);
+ if (keyRing == null) {
+ return null;
+ }
+ PGPSecretKey masterKey = getMasterKey(keyRing);
+ if (masterKey == null) {
+ return null;
+ }
+ realId = masterKey.getKeyID();
+ }
+ CachedPassPhrase cpp = mPassPhraseCache.get(realId);
+ if (cpp == null) {
+ return null;
+ }
+ // set it again to reset the cache life cycle
+ setCachedPassPhrase(realId, cpp.passPhrase);
+ return cpp.passPhrase;
+ }
+
+ public static void cleanUpCache(int ttl) {
+ long now = new Date().getTime();
+
+ Vector<Long> oldKeys = new Vector<Long>();
+ for (Map.Entry<Long, CachedPassPhrase> pair : mPassPhraseCache.entrySet()) {
+ if ((now - pair.getValue().timestamp) >= 1000 * ttl) {
+ oldKeys.add(pair.getKey());
+ }
+ }
+
+ for (long keyId : oldKeys) {
+ mPassPhraseCache.remove(keyId);
+ }
+ }
+
+ public static PGPSecretKey createKey(Context context,
+ int algorithmChoice, int keySize, String passPhrase,
+ PGPSecretKey masterKey)
throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
GeneralException, InvalidAlgorithmParameterException {
- if (algorithmChoice == null) {
- throw new GeneralException("unknown algorithm choice");
- }
if (keySize < 512) {
- throw new GeneralException("key size must be at least 512bit");
+ throw new GeneralException(context.getString(R.string.error_keySizeMinimum512bit));
}
Security.addProvider(new BouncyCastleProvider());
@@ -283,34 +342,30 @@ public class Apg { int algorithm = 0;
KeyPairGenerator keyGen = null;
- switch (algorithmChoice.getId()) {
- case KeyEditor.AlgorithmChoice.DSA: {
+ switch (algorithmChoice) {
+ case Id.choice.algorithm.dsa: {
keyGen = KeyPairGenerator.getInstance("DSA", new BouncyCastleProvider());
keyGen.initialize(keySize, new SecureRandom());
algorithm = PGPPublicKey.DSA;
break;
}
- case KeyEditor.AlgorithmChoice.ELGAMAL: {
- if (keySize != 2048) {
- throw new GeneralException("ElGamal currently requires 2048bit");
+ case Id.choice.algorithm.elgamal: {
+ if (masterKey == null) {
+ throw new GeneralException(context.getString(R.string.error_masterKeyMustNotBeElGamal));
}
keyGen = KeyPairGenerator.getInstance("ELGAMAL", new BouncyCastleProvider());
- BigInteger p = new BigInteger(
- "36F0255DDE973DCB3B399D747F23E32ED6FDB1F77598338BFDF44159C4EC64DDAEB5F78671CBFB22" +
- "106AE64C32C5BCE4CFD4F5920DA0EBC8B01ECA9292AE3DBA1B7A4A899DA181390BB3BD1659C81294" +
- "F400A3490BF9481211C79404A576605A5160DBEE83B4E019B6D799AE131BA4C23DFF83475E9C40FA" +
- "6725B7C9E3AA2C6596E9C05702DB30A07C9AA2DC235C5269E39D0CA9DF7AAD44612AD6F88F696992" +
- "98F3CAB1B54367FB0E8B93F735E7DE83CD6FA1B9D1C931C41C6188D3E7F179FC64D87C5D13F85D70" +
- "4A3AA20F90B3AD3621D434096AA7E8E7C66AB683156A951AEA2DD9E76705FAEFEA8D71A575535597" +
- "0000000000000001", 16);
- ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, new BigInteger("2"));
+ BigInteger p = Primes.getBestPrime(keySize);
+ BigInteger g = new BigInteger("2");
+
+ ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
+
keyGen.initialize(elParams);
- algorithm = PGPPublicKey.ELGAMAL_GENERAL;
+ algorithm = PGPPublicKey.ELGAMAL_ENCRYPT;
break;
}
- case KeyEditor.AlgorithmChoice.RSA: {
+ case Id.choice.algorithm.rsa: {
keyGen = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
keyGen.initialize(keySize, new SecureRandom());
@@ -319,17 +374,45 @@ public class Apg { }
default: {
- throw new GeneralException("unknown algorithm choice");
+ throw new GeneralException(context.getString(R.string.error_unknownAlgorithmChoice));
}
}
PGPKeyPair keyPair = new PGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date());
- // enough for now, as we assemble the key again later anyway
- PGPSecretKey secretKey =
- new PGPSecretKey(PGPSignature.DEFAULT_CERTIFICATION, keyPair, "",
- PGPEncryptedData.CAST5, passPhrase.toCharArray(), null, null,
- new SecureRandom(), new BouncyCastleProvider().getName());
+ PGPSecretKey secretKey = null;
+ if (masterKey == null) {
+ // enough for now, as we assemble the key again later anyway
+ secretKey = new PGPSecretKey(PGPSignature.DEFAULT_CERTIFICATION, keyPair, "",
+ PGPEncryptedData.CAST5, passPhrase.toCharArray(),
+ null, null,
+ new SecureRandom(), new BouncyCastleProvider().getName());
+
+ } else {
+ PGPPublicKey tmpKey = masterKey.getPublicKey();
+ PGPPublicKey masterPublicKey =
+ new PGPPublicKey(tmpKey.getAlgorithm(),
+ tmpKey.getKey(new BouncyCastleProvider()),
+ tmpKey.getCreationTime());
+ PGPPrivateKey masterPrivateKey =
+ masterKey.extractPrivateKey(passPhrase.toCharArray(),
+ new BouncyCastleProvider());
+
+ PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey);
+ PGPKeyRingGenerator ringGen =
+ new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
+ masterKeyPair, "",
+ PGPEncryptedData.CAST5, passPhrase.toCharArray(),
+ null, null,
+ new SecureRandom(), new BouncyCastleProvider().getName());
+ ringGen.addSubKey(keyPair);
+ PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing();
+ Iterator it = secKeyRing.getSecretKeys();
+ // first one is the master key
+ it.next();
+ secretKey = (PGPSecretKey) it.next();
+ }
+
return secretKey;
}
@@ -353,7 +436,7 @@ public class Apg { throws Apg.GeneralException, NoSuchProviderException, PGPException,
NoSuchAlgorithmException, SignatureException {
- progress.setProgress("building key...", 0, 100);
+ progress.setProgress(R.string.progress_buildingKey, 0, 100);
Security.addProvider(new BouncyCastleProvider());
@@ -378,9 +461,9 @@ public class Apg { try {
userId = editor.getValue();
} catch (UserIdEditor.NoNameException e) {
- throw new Apg.GeneralException("you need to specify a name");
+ throw new Apg.GeneralException(context.getString(R.string.error_userIdNeedsAName));
} catch (UserIdEditor.NoEmailException e) {
- throw new Apg.GeneralException("you need to specify an email");
+ throw new Apg.GeneralException(context.getString(R.string.error_userIdNeedsAnEmailAddress));
} catch (UserIdEditor.InvalidEmailException e) {
throw new Apg.GeneralException(e.getMessage());
}
@@ -398,15 +481,15 @@ public class Apg { }
if (userIds.size() == 0) {
- throw new Apg.GeneralException("need at least one user id");
+ throw new Apg.GeneralException(context.getString(R.string.error_keyNeedsAUserId));
}
if (!gotMainUserId) {
- throw new Apg.GeneralException("main user id can't be empty");
+ throw new Apg.GeneralException(context.getString(R.string.error_mainUserIdMustNotBeEmpty));
}
if (keyEditors.getChildCount() == 0) {
- throw new Apg.GeneralException("need at least a main key");
+ throw new Apg.GeneralException(context.getString(R.string.error_keyNeedsMasterKey));
}
for (int i = 0; i < keyEditors.getChildCount(); ++i) {
@@ -414,13 +497,13 @@ public class Apg { keys.add(editor.getValue());
}
- progress.setProgress("preparing master key...", 10, 100);
+ progress.setProgress(R.string.progress_preparingMasterKey, 10, 100);
KeyEditor keyEditor = (KeyEditor) keyEditors.getChildAt(0);
- int usageId = keyEditor.getUsage().getId();
- boolean canSign = (usageId == KeyEditor.UsageChoice.SIGN_ONLY ||
- usageId == KeyEditor.UsageChoice.SIGN_AND_ENCRYPT);
- boolean canEncrypt = (usageId == KeyEditor.UsageChoice.ENCRYPT_ONLY ||
- usageId == KeyEditor.UsageChoice.SIGN_AND_ENCRYPT);
+ int usageId = keyEditor.getUsage();
+ boolean canSign = (usageId == Id.choice.usage.sign_only ||
+ usageId == Id.choice.usage.sign_and_encrypt);
+ boolean canEncrypt = (usageId == Id.choice.usage.encrypt_only ||
+ usageId == Id.choice.usage.sign_and_encrypt);
String mainUserId = userIds.get(0);
@@ -434,7 +517,7 @@ public class Apg { masterKey.extractPrivateKey(oldPassPhrase.toCharArray(),
new BouncyCastleProvider());
- progress.setProgress("certifying master key...", 20, 100);
+ progress.setProgress(R.string.progress_certifyingMasterKey, 20, 100);
for (int i = 0; i < userIds.size(); ++i) {
String userId = userIds.get(i);
@@ -472,20 +555,20 @@ public class Apg { GregorianCalendar expiryDate = keyEditor.getExpiryDate();
long numDays = getNumDatesBetween(creationDate, expiryDate);
if (numDays <= 0) {
- throw new GeneralException("expiry date must be later than creation date");
+ throw new GeneralException(context.getString(R.string.error_expiryMustComeAfterCreation));
}
hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400);
}
- progress.setProgress("building master key ring...", 30, 100);
+ progress.setProgress(R.string.progress_buildingMasterKeyRing, 30, 100);
PGPKeyRingGenerator keyGen =
- new PGPKeyRingGenerator(PGPSignature.DEFAULT_CERTIFICATION,
+ new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
masterKeyPair, mainUserId,
PGPEncryptedData.CAST5, newPassPhrase.toCharArray(),
hashedPacketsGen.generate(), unhashedPacketsGen.generate(),
new SecureRandom(), new BouncyCastleProvider().getName());
- progress.setProgress("adding sub keys...", 40, 100);
+ progress.setProgress(R.string.progress_addingSubKeys, 40, 100);
for (int i = 1; i < keys.size(); ++i) {
progress.setProgress(40 + 50 * (i - 1)/ (keys.size() - 1), 100);
PGPSecretKey subKey = keys.get(i);
@@ -504,11 +587,11 @@ public class Apg { unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
keyFlags = 0;
- usageId = keyEditor.getUsage().getId();
- canSign = (usageId == KeyEditor.UsageChoice.SIGN_ONLY ||
- usageId == KeyEditor.UsageChoice.SIGN_AND_ENCRYPT);
- canEncrypt = (usageId == KeyEditor.UsageChoice.ENCRYPT_ONLY ||
- usageId == KeyEditor.UsageChoice.SIGN_AND_ENCRYPT);
+ usageId = keyEditor.getUsage();
+ canSign = (usageId == Id.choice.usage.sign_only ||
+ usageId == Id.choice.usage.sign_and_encrypt);
+ canEncrypt = (usageId == Id.choice.usage.encrypt_only ||
+ usageId == Id.choice.usage.sign_and_encrypt);
if (canSign) {
keyFlags |= KeyFlags.SIGN_DATA;
}
@@ -523,7 +606,7 @@ public class Apg { GregorianCalendar expiryDate = keyEditor.getExpiryDate();
long numDays = getNumDatesBetween(creationDate, expiryDate);
if (numDays <= 0) {
- throw new GeneralException("expiry date must be later than creation date");
+ throw new GeneralException(context.getString(R.string.error_expiryMustComeAfterCreation));
}
hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400);
}
@@ -535,13 +618,13 @@ public class Apg { PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing();
PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing();
- progress.setProgress("saving key ring...", 90, 100);
+ progress.setProgress(R.string.progress_savingKeyRing, 90, 100);
saveKeyRing(context, secretKeyRing);
saveKeyRing(context, publicKeyRing);
- loadKeyRings(context, TYPE_PUBLIC);
- loadKeyRings(context, TYPE_SECRET);
- progress.setProgress("done.", 100, 100);
+ loadKeyRings(context, Id.type.public_key);
+ loadKeyRings(context, Id.type.secret_key);
+ progress.setProgress(R.string.progress_done, 100, 100);
}
private static int saveKeyRing(Activity context, PGPPublicKeyRing keyRing) {
@@ -550,14 +633,14 @@ public class Apg { PGPPublicKey masterKey = getMasterKey(keyRing);
if (masterKey == null) {
- return RETURN_NO_MASTER_KEY;
+ return Id.return_value.no_master_key;
}
try {
keyRing.encode(out);
out.close();
} catch (IOException e) {
- return RETURN_ERROR;
+ return Id.return_value.error;
}
values.put(PublicKeys.KEY_ID, masterKey.getKeyID());
@@ -567,10 +650,10 @@ public class Apg { Cursor cursor = context.managedQuery(uri, PUBLIC_KEY_PROJECTION, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
context.getContentResolver().update(uri, values, null, null);
- return RETURN_UPDATED;
+ return Id.return_value.updated;
} else {
context.getContentResolver().insert(PublicKeys.CONTENT_URI, values);
- return RETURN_OK;
+ return Id.return_value.ok;
}
}
@@ -580,14 +663,14 @@ public class Apg { PGPSecretKey masterKey = getMasterKey(keyRing);
if (masterKey == null) {
- return RETURN_NO_MASTER_KEY;
+ return Id.return_value.no_master_key;
}
try {
keyRing.encode(out);
out.close();
} catch (IOException e) {
- return RETURN_ERROR;
+ return Id.return_value.error;
}
values.put(SecretKeys.KEY_ID, masterKey.getKeyID());
@@ -597,10 +680,10 @@ public class Apg { Cursor cursor = context.managedQuery(uri, SECRET_KEY_PROJECTION, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
context.getContentResolver().update(uri, values, null, null);
- return RETURN_UPDATED;
+ return Id.return_value.updated;
} else {
context.getContentResolver().insert(SecretKeys.CONTENT_URI, values);
- return RETURN_OK;
+ return Id.return_value.ok;
}
}
@@ -608,27 +691,27 @@ public class Apg { ProgressDialogUpdater progress)
throws GeneralException, FileNotFoundException, PGPException, IOException {
Bundle returnData = new Bundle();
- PGPObjectFactory objectFactors = null;
+ PGPObjectFactory objectFactory = null;
- if (type == TYPE_SECRET) {
- progress.setProgress("importing secret keys...", 0, 100);
+ if (type == Id.type.secret_key) {
+ progress.setProgress(R.string.progress_importingSecretKeys, 0, 100);
} else {
- progress.setProgress("importing public keys...", 0, 100);
+ progress.setProgress(R.string.progress_importingPublicKeys, 0, 100);
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new GeneralException("external storage not ready");
+ throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
}
FileInputStream fileIn = new FileInputStream(filename);
InputStream in = PGPUtil.getDecoderStream(fileIn);
- objectFactors = new PGPObjectFactory(in);
+ objectFactory = new PGPObjectFactory(in);
Vector<Object> objects = new Vector<Object>();
- Object obj = objectFactors.nextObject();
+ Object obj = objectFactory.nextObject();
while (obj != null) {
objects.add(obj);
- obj = objectFactors.nextObject();
+ obj = objectFactory.nextObject();
}
int newKeys = 0;
@@ -640,7 +723,7 @@ public class Apg { PGPSecretKeyRing secretKeyRing;
int retValue;
- if (type == TYPE_SECRET) {
+ if (type == Id.type.secret_key) {
if (!(obj instanceof PGPSecretKeyRing)) {
continue;
}
@@ -654,24 +737,24 @@ public class Apg { retValue = saveKeyRing(context, publicKeyRing);
}
- if (retValue == RETURN_ERROR) {
- throw new GeneralException("error saving some key(s)");
+ if (retValue == Id.return_value.error) {
+ throw new GeneralException(context.getString(R.string.error_savingKeys));
}
- if (retValue == RETURN_UPDATED) {
+ if (retValue == Id.return_value.updated) {
++oldKeys;
- } else if (retValue == RETURN_OK) {
+ } else if (retValue == Id.return_value.ok) {
++newKeys;
}
}
- progress.setProgress("reloading keys...", 100, 100);
+ progress.setProgress(R.string.progress_reloadingKeys, 100, 100);
loadKeyRings(context, type);
returnData.putInt("added", newKeys);
returnData.putInt("updated", oldKeys);
- progress.setProgress("done.", 100, 100);
+ progress.setProgress(R.string.progress_done, 100, 100);
return returnData;
}
@@ -682,13 +765,13 @@ public class Apg { Bundle returnData = new Bundle();
if (keys.size() == 1) {
- progress.setProgress("exporting key...", 0, 100);
+ progress.setProgress(R.string.progress_exportingKey, 0, 100);
} else {
- progress.setProgress("exporting keys...", 0, 100);
+ progress.setProgress(R.string.progress_exportingKeys, 0, 100);
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new GeneralException("external storage not ready");
+ throw new GeneralException(context.getString(R.string.error_externalStorageNotReady));
}
FileOutputStream fileOut = new FileOutputStream(new File(filename), false);
ArmoredOutputStream out = new ArmoredOutputStream(fileOut);
@@ -715,14 +798,14 @@ public class Apg { fileOut.close();
returnData.putInt("exported", numKeys);
- progress.setProgress("done.", 100, 100);
+ progress.setProgress(R.string.progress_done, 100, 100);
return returnData;
}
private static void loadKeyRings(Activity context, int type) {
Cursor cursor;
- if (type == TYPE_SECRET) {
+ if (type == Id.type.secret_key) {
mSecretKeyRings.clear();
mSecretKeyIdToIdMap.clear();
mSecretKeyIdToKeyRingMap.clear();
@@ -750,7 +833,7 @@ public class Apg { long keyId = cursor.getLong(keyIdIndex);
try {
- if (type == TYPE_SECRET) {
+ if (type == Id.type.secret_key) {
PGPSecretKeyRing key = new PGPSecretKeyRing(keyData);
mSecretKeyRings.add(key);
mSecretKeyIdToIdMap.put(keyId, id);
@@ -768,7 +851,7 @@ public class Apg { }
}
- if (type == TYPE_SECRET) {
+ if (type == Id.type.secret_key) {
Collections.sort(mSecretKeyRings, new SecretKeySorter());
} else {
Collections.sort(mPublicKeyRings, new PublicKeySorter());
@@ -939,7 +1022,7 @@ public class Apg { public static String getMainUserIdSafe(Context context, PGPPublicKey key) {
String userId = getMainUserId(key);
if (userId == null) {
- userId = context.getResources().getString(R.string.unknown_user_id);
+ userId = context.getResources().getString(R.string.unknownUserId);
}
return userId;
}
@@ -947,7 +1030,7 @@ public class Apg { public static String getMainUserIdSafe(Context context, PGPSecretKey key) {
String userId = getMainUserId(key);
if (userId == null) {
- userId = context.getResources().getString(R.string.unknown_user_id);
+ userId = context.getResources().getString(R.string.unknownUserId);
}
return userId;
}
@@ -970,19 +1053,31 @@ public class Apg { return key.isEncryptionKey();
}
- // special case, this algorithm, no need to look further
+ // special cases
if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
return true;
}
+ if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
+ return true;
+ }
+
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (!key.isMasterKey() || sig.getKeyID() == key.getKeyID()) {
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
+ if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
+ continue;
+ }
+ PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
- if ((hashed.getKeyFlags() &
- (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
- return true;
- }
+ if (hashed != null &&(hashed.getKeyFlags() &
+ (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
+ return true;
+ }
+
+ PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
+
+ if (unhashed != null &&(unhashed.getKeyFlags() &
+ (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
+ return true;
}
}
return false;
@@ -997,13 +1092,25 @@ public class Apg { return true;
}
+ // special case
+ if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
+ return true;
+ }
+
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (!key.isMasterKey() || sig.getKeyID() == key.getKeyID()) {
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
+ if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
+ continue;
+ }
+ PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
- if ((hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
- return true;
- }
+ if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
+ return true;
+ }
+
+ PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
+
+ if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
+ return true;
}
}
@@ -1052,14 +1159,14 @@ public class Apg { PGPPublicKey masterKey = getMasterKey(keyRing);
Uri uri = Uri.withAppendedPath(PublicKeys.CONTENT_URI_BY_KEY_ID, "" + masterKey.getKeyID());
context.getContentResolver().delete(uri, null, null);
- loadKeyRings(context, TYPE_PUBLIC);
+ loadKeyRings(context, Id.type.public_key);
}
public static void deleteKey(Activity context, PGPSecretKeyRing keyRing) {
PGPSecretKey masterKey = getMasterKey(keyRing);
Uri uri = Uri.withAppendedPath(SecretKeys.CONTENT_URI_BY_KEY_ID, "" + masterKey.getKeyID());
context.getContentResolver().delete(uri, null, null);
- loadKeyRings(context, TYPE_SECRET);
+ loadKeyRings(context, Id.type.secret_key);
}
public static PGPPublicKey findPublicKey(long keyId) {
@@ -1134,59 +1241,67 @@ public class Apg { return null;
}
- public static void encrypt(InputStream inStream, OutputStream outStream,
+ public static void encrypt(Context context,
+ InputStream inStream, OutputStream outStream,
+ long dataLength,
+ boolean armored,
long encryptionKeyIds[], long signatureKeyId,
String signaturePassPhrase,
- ProgressDialogUpdater progress)
+ ProgressDialogUpdater progress,
+ int symmetricAlgorithm, int hashAlgorithm, int compression,
+ String passPhrase)
throws IOException, GeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
Security.addProvider(new BouncyCastleProvider());
- ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
- armorOut.setHeader("Version", FULL_VERSION);
- OutputStream out = armorOut;
- OutputStream encryptOut = null;
+ if (encryptionKeyIds == null) {
+ encryptionKeyIds = new long[0];
+ }
+ ArmoredOutputStream armorOut = null;
+ OutputStream out = null;
+ OutputStream encryptOut = null;
+ if (armored) {
+ armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", FULL_VERSION);
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
PGPSecretKey signingKey = null;
PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null;
- if (encryptionKeyIds == null || encryptionKeyIds.length == 0) {
- throw new GeneralException("no encryption key(s) given");
+ if (encryptionKeyIds.length == 0 && passPhrase == null) {
+ throw new GeneralException(context.getString(R.string.error_noEncryptionKeysOrPassPhrase));
}
if (signatureKeyId != 0) {
signingKeyRing = findSecretKeyRing(signatureKeyId);
signingKey = getSigningKey(signatureKeyId);
if (signingKey == null) {
- throw new GeneralException("signature failed");
+ throw new GeneralException(context.getString(R.string.error_signatureFailed));
}
if (signaturePassPhrase == null) {
- throw new GeneralException("no pass phrase given");
+ throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
}
+ progress.setProgress(R.string.progress_extractingSignatureKey, 0, 100);
signaturePrivateKey = signingKey.extractPrivateKey(signaturePassPhrase.toCharArray(),
new BouncyCastleProvider());
}
PGPSignatureGenerator signatureGenerator = null;
- progress.setProgress("preparing data...", 0, 100);
-
- ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
- int n = 0;
- byte[] buffer = new byte[1 << 16];
- while ((n = inStream.read(buffer)) > 0) {
- byteOut.write(buffer, 0, n);
- }
- byteOut.close();
- byte messageData[] = byteOut.toByteArray();
-
- progress.setProgress("preparing streams...", 20, 100);
- // encryptFile and compress input file content
+ progress.setProgress(R.string.progress_preparingStreams, 5, 100);
+ // encrypt and compress input file content
PGPEncryptedDataGenerator cPk =
- new PGPEncryptedDataGenerator(PGPEncryptedData.AES_256, true, new SecureRandom(),
+ new PGPEncryptedDataGenerator(symmetricAlgorithm, true, new SecureRandom(),
new BouncyCastleProvider());
+ if (encryptionKeyIds.length == 0) {
+ // symmetric encryption
+ cPk.addMethod(passPhrase.toCharArray());
+ }
for (int i = 0; i < encryptionKeyIds.length; ++i) {
PGPPublicKey key = getEncryptPublicKey(encryptionKeyIds[i]);
if (key != null) {
@@ -1196,10 +1311,10 @@ public class Apg { encryptOut = cPk.open(out, new byte[1 << 16]);
if (signatureKeyId != 0) {
- progress.setProgress("preparing signature...", 30, 100);
+ progress.setProgress(R.string.progress_preparingSignature, 10, 100);
signatureGenerator =
new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
- HashAlgorithmTags.SHA1,
+ hashAlgorithm,
new BouncyCastleProvider());
signatureGenerator.initSign(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
String userId = getMainUserId(getMasterKey(signingKeyRing));
@@ -1209,9 +1324,14 @@ public class Apg { signatureGenerator.setHashedSubpackets(spGen.generate());
}
- PGPCompressedDataGenerator compressGen =
- new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZLIB);
- BCPGOutputStream bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
+ PGPCompressedDataGenerator compressGen = null;
+ BCPGOutputStream bcpgOut = null;
+ if (compression == Id.choice.compression.none) {
+ bcpgOut = new BCPGOutputStream(encryptOut);
+ } else {
+ compressGen = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZLIB);
+ bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
+ }
if (signatureKeyId != 0) {
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
}
@@ -1219,68 +1339,80 @@ public class Apg { PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
// file name not needed, so empty string
OutputStream pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "",
- messageData.length, new Date());
-
- progress.setProgress("encrypting...", 40, 100);
- pOut.write(messageData);
+ new Date(), new byte[1 << 16]);
- if (signatureKeyId != 0) {
- progress.setProgress("finishing signature...", 70, 100);
- signatureGenerator.update(messageData);
+ progress.setProgress(R.string.progress_encrypting, 20, 100);
+ long done = 0;
+ int n = 0;
+ byte[] buffer = new byte[1 << 16];
+ while ((n = inStream.read(buffer)) > 0) {
+ pOut.write(buffer, 0, n);
+ if (signatureKeyId != 0) {
+ signatureGenerator.update(buffer, 0, n);
+ }
+ done += n;
+ if (dataLength != 0) {
+ progress.setProgress((int) (20 + (95 - 20) * done / dataLength), 100);
+ }
}
literalGen.close();
if (signatureKeyId != 0) {
+ progress.setProgress(R.string.progress_generatingSignature, 95, 100);
signatureGenerator.generate().encode(pOut);
}
- compressGen.close();
+ if (compressGen != null) {
+ compressGen.close();
+ }
encryptOut.close();
- out.close();
+ if (armored) {
+ armorOut.close();
+ }
- progress.setProgress("done.", 100, 100);
+ progress.setProgress(R.string.progress_done, 100, 100);
}
- public static void sign(InputStream inStream, OutputStream outStream,
- long signatureKeyId, String signaturePassPhrase,
- ProgressDialogUpdater progress)
+ public static void signText(Context context,
+ InputStream inStream, OutputStream outStream,
+ long signatureKeyId, String signaturePassPhrase,
+ int hashAlgorithm,
+ ProgressDialogUpdater progress)
throws GeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException {
Security.addProvider(new BouncyCastleProvider());
ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
armorOut.setHeader("Version", FULL_VERSION);
- OutputStream out = armorOut;
- OutputStream signOut = out;
PGPSecretKey signingKey = null;
PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null;
if (signatureKeyId == 0) {
- throw new GeneralException("no signature key given");
+ throw new GeneralException(context.getString(R.string.error_noSignatureKey));
}
signingKeyRing = findSecretKeyRing(signatureKeyId);
signingKey = getSigningKey(signatureKeyId);
if (signingKey == null) {
- throw new GeneralException("signature failed");
+ throw new GeneralException(context.getString(R.string.error_signatureFailed));
}
if (signaturePassPhrase == null) {
- throw new GeneralException("no pass phrase given");
+ throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
}
signaturePrivateKey =
signingKey.extractPrivateKey(signaturePassPhrase.toCharArray(),
new BouncyCastleProvider());
PGPSignatureGenerator signatureGenerator = null;
- progress.setProgress("preparing data...", 0, 100);
+ progress.setProgress(R.string.progress_preparingStreams, 0, 100);
- progress.setProgress("preparing signature...", 30, 100);
+ progress.setProgress(R.string.progress_preparingSignature, 30, 100);
signatureGenerator =
new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
- HashAlgorithmTags.SHA1,
+ hashAlgorithm,
new BouncyCastleProvider());
signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
String userId = getMainUserId(getMasterKey(signingKeyRing));
@@ -1289,22 +1421,38 @@ public class Apg { spGen.setSignerUserID(false, userId);
signatureGenerator.setHashedSubpackets(spGen.generate());
- progress.setProgress("signing...", 40, 100);
- int n = 0;
- byte[] buffer = new byte[1 << 16];
- while ((n = inStream.read(buffer)) > 0) {
- signatureGenerator.update(buffer, 0, n);
+ progress.setProgress(R.string.progress_signing, 40, 100);
+
+ armorOut.beginClearText(hashAlgorithm);
+
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, inStream);
+
+ processLine(armorOut, signatureGenerator, lineOut.toByteArray());
+
+ if (lookAhead != -1) {
+ do {
+ lookAhead = readInputLine(lineOut, lookAhead, inStream);
+
+ signatureGenerator.update((byte)'\r');
+ signatureGenerator.update((byte)'\n');
+
+ processLine(armorOut, signatureGenerator, lineOut.toByteArray());
+ }
+ while (lookAhead != -1);
}
- signatureGenerator.generate().encode(signOut);
- signOut.close();
- out.close();
+ armorOut.endClearText();
- progress.setProgress("done.", 100, 100);
+ BCPGOutputStream bOut = new BCPGOutputStream(armorOut);
+ signatureGenerator.generate().encode(bOut);
+ armorOut.close();
+
+ progress.setProgress(R.string.progress_done, 100, 100);
}
- public static long getDecryptionKeyId(InputStream inStream)
- throws GeneralException, IOException {
+ public static long getDecryptionKeyId(Context context, InputStream inStream)
+ throws GeneralException, NoAsymmetricEncryptionException, IOException {
InputStream in = PGPUtil.getDecoderStream(inStream);
PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc;
@@ -1318,27 +1466,71 @@ public class Apg { }
if (enc == null) {
- throw new GeneralException("data not valid encryption data");
+ throw new GeneralException(context.getString(R.string.error_invalidData));
}
+ // TODO: currently we always only look at the first known key
// find the secret key
PGPSecretKey secretKey = null;
- for (PGPPublicKeyEncryptedData pbe :
- new IterableIterator<PGPPublicKeyEncryptedData>(enc.getEncryptedDataObjects())) {
- secretKey = findSecretKey(pbe.getKeyID());
- if (secretKey != null) {
- break;
+ Iterator it = enc.getEncryptedDataObjects();
+ boolean gotAsymmetricEncryption = false;
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPublicKeyEncryptedData) {
+ gotAsymmetricEncryption = true;
+ PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj;
+ secretKey = findSecretKey(pbe.getKeyID());
+ if (secretKey != null) {
+ break;
+ }
}
}
+
+ if (!gotAsymmetricEncryption) {
+ throw new NoAsymmetricEncryptionException();
+ }
+
if (secretKey == null) {
- throw new GeneralException("couldn't find a secret key to decrypt");
+ return Id.key.none;
}
return secretKey.getKeyID();
}
- public static Bundle decrypt(InputStream inStream, OutputStream outStream,
- String passPhrase, ProgressDialogUpdater progress)
+ public static boolean hasSymmetricEncryption(Context context, InputStream inStream)
+ throws GeneralException, IOException {
+ InputStream in = PGPUtil.getDecoderStream(inStream);
+ PGPObjectFactory pgpF = new PGPObjectFactory(in);
+ PGPEncryptedDataList enc;
+ Object o = pgpF.nextObject();
+
+ // the first object might be a PGP marker packet.
+ if (o instanceof PGPEncryptedDataList) {
+ enc = (PGPEncryptedDataList) o;
+ } else {
+ enc = (PGPEncryptedDataList) pgpF.nextObject();
+ }
+
+ if (enc == null) {
+ throw new GeneralException(context.getString(R.string.error_invalidData));
+ }
+
+ Iterator it = enc.getEncryptedDataObjects();
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPBEEncryptedData) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static Bundle decrypt(Context context,
+ PositionAwareInputStream inStream, OutputStream outStream,
+ long dataLength,
+ String passPhrase, ProgressDialogUpdater progress,
+ boolean assumeSymmetric)
throws IOException, GeneralException, PGPException, SignatureException {
Bundle returnData = new Bundle();
InputStream in = PGPUtil.getDecoderStream(inStream);
@@ -1347,7 +1539,8 @@ public class Apg { Object o = pgpF.nextObject();
long signatureKeyId = 0;
- progress.setProgress("reading data...", 0, 100);
+ int currentProgress = 0;
+ progress.setProgress(R.string.progress_readingData, currentProgress, 100);
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
@@ -1356,35 +1549,74 @@ public class Apg { }
if (enc == null) {
- throw new GeneralException("data not valid encryption data");
+ throw new GeneralException(context.getString(R.string.error_invalidData));
}
- progress.setProgress("finding key...", 10, 100);
- // find the secret key
- PGPPublicKeyEncryptedData pbe = null;
- PGPSecretKey secretKey = null;
- for (PGPPublicKeyEncryptedData encData :
- new IterableIterator<PGPPublicKeyEncryptedData>(enc.getEncryptedDataObjects())) {
- secretKey = findSecretKey(encData.getKeyID());
- if (secretKey != null) {
- pbe = encData;
- break;
+ InputStream clear = null;
+ PGPEncryptedData encryptedData = null;
+
+ currentProgress += 5;
+
+ // TODO: currently we always only look at the first known key or symmetric encryption,
+ // there might be more...
+ if (assumeSymmetric) {
+ PGPPBEEncryptedData pbe = null;
+ Iterator it = enc.getEncryptedDataObjects();
+ // find secret key
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPBEEncryptedData) {
+ pbe = (PGPPBEEncryptedData) obj;
+ break;
+ }
}
- }
- if (secretKey == null) {
- throw new GeneralException("couldn't find a secret key to decrypt");
- }
- progress.setProgress("extracting key...", 20, 100);
- PGPPrivateKey privateKey = null;
- try {
- privateKey = secretKey.extractPrivateKey(passPhrase.toCharArray(),
- new BouncyCastleProvider());
- } catch (PGPException e) {
- throw new PGPException("wrong pass phrase");
+ if (pbe == null) {
+ throw new GeneralException(context.getString(R.string.error_noSymmetricEncryptionPacket));
+ }
+
+ progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100);
+ clear = pbe.getDataStream(passPhrase.toCharArray(), new BouncyCastleProvider());
+ encryptedData = pbe;
+ currentProgress += 5;
+ } else {
+ progress.setProgress(R.string.progress_findingKey, currentProgress, 100);
+ PGPPublicKeyEncryptedData pbe = null;
+ PGPSecretKey secretKey = null;
+ Iterator it = enc.getEncryptedDataObjects();
+ // find secret key
+ while (it.hasNext()) {
+ Object obj = it.next();
+ if (obj instanceof PGPPublicKeyEncryptedData) {
+ PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
+ secretKey = findSecretKey(encData.getKeyID());
+ if (secretKey != null) {
+ pbe = encData;
+ break;
+ }
+ }
+ }
+
+ if (secretKey == null) {
+ throw new GeneralException(context.getString(R.string.error_noSecretKeyFound));
+ }
+
+ currentProgress += 5;
+ progress.setProgress(R.string.progress_extractingKey, currentProgress, 100);
+ PGPPrivateKey privateKey = null;
+ try {
+ privateKey = secretKey.extractPrivateKey(passPhrase.toCharArray(),
+ new BouncyCastleProvider());
+ } catch (PGPException e) {
+ throw new PGPException(context.getString(R.string.error_wrongPassPhrase));
+ }
+ currentProgress += 5;
+ progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100);
+ clear = pbe.getDataStream(privateKey, new BouncyCastleProvider());
+ encryptedData = pbe;
+ currentProgress += 5;
}
- progress.setProgress("decrypting data...", 30, 100);
- InputStream clear = pbe.getDataStream(privateKey, new BouncyCastleProvider());
+
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
Object dataChunk = plainFact.nextObject();
PGPOnePassSignature signature = null;
@@ -1392,15 +1624,16 @@ public class Apg { int signatureIndex = -1;
if (dataChunk instanceof PGPCompressedData) {
- progress.setProgress("decompressing data...", 50, 100);
+ progress.setProgress(R.string.progress_decompressingData, currentProgress, 100);
PGPObjectFactory fact =
new PGPObjectFactory(((PGPCompressedData) dataChunk).getDataStream());
dataChunk = fact.nextObject();
plainFact = fact;
+ currentProgress += 10;
}
if (dataChunk instanceof PGPOnePassSignatureList) {
- progress.setProgress("processing signature...", 60, 100);
+ progress.setProgress(R.string.progress_processingSignature, currentProgress, 100);
returnData.putBoolean("signature", true);
PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
for (int i = 0; i < sigList.size(); ++i) {
@@ -1433,33 +1666,51 @@ public class Apg { }
dataChunk = plainFact.nextObject();
+ currentProgress += 10;
}
if (dataChunk instanceof PGPLiteralData) {
- progress.setProgress("unpacking data...", 70, 100);
+ progress.setProgress(R.string.progress_decrypting, currentProgress, 100);
PGPLiteralData literalData = (PGPLiteralData) dataChunk;
- BufferedOutputStream out = new BufferedOutputStream(outStream);
+ OutputStream out = outStream;
byte[] buffer = new byte[1 << 16];
InputStream dataIn = literalData.getInputStream();
- int bytesRead = 0;
- while ((bytesRead = dataIn.read(buffer)) > 0) {
- out.write(buffer, 0, bytesRead);
+ int startProgress = currentProgress;
+ int endProgress = 100;
+ if (signature != null) {
+ endProgress = 90;
+ } else if (encryptedData.isIntegrityProtected()) {
+ endProgress = 95;
+ }
+ int n = 0;
+ int done = 0;
+ long startPos = inStream.position();
+ while ((n = dataIn.read(buffer)) > 0) {
+ out.write(buffer, 0, n);
+ done += n;
if (signature != null) {
try {
- signature.update(buffer, 0, bytesRead);
+ signature.update(buffer, 0, n);
} catch (SignatureException e) {
returnData.putBoolean("signatureSuccess", false);
signature = null;
}
}
+ // unknown size, but try to at least have a moving, slowing down progress bar
+ currentProgress = startProgress + (endProgress - startProgress) * done / (done + 100000);
+ if (dataLength - startPos == 0) {
+ currentProgress = endProgress;
+ } else {
+ currentProgress = (int)(startProgress + (endProgress - startProgress) *
+ (inStream.position() - startPos) / (dataLength - startPos));
+ }
+ progress.setProgress(currentProgress, 100);
}
- out.close();
-
if (signature != null) {
- progress.setProgress("verifying signature...", 80, 100);
+ progress.setProgress(R.string.progress_verifyingSignature, 90, 100);
PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
PGPSignature messageSignature = (PGPSignature) signatureList.get(signatureIndex);
if (signature.verify(messageSignature)) {
@@ -1471,18 +1722,116 @@ public class Apg { }
// TODO: add integrity somewhere
- if (pbe.isIntegrityProtected()) {
- progress.setProgress("verifying integrity...", 90, 100);
- if (!pbe.verify()) {
- System.err.println("message failed integrity check");
+ if (encryptedData.isIntegrityProtected()) {
+ progress.setProgress(R.string.progress_verifyingIntegrity, 95, 100);
+ if (encryptedData.verify()) {
+ // passed
} else {
- System.err.println("message integrity check passed");
+ // failed
}
} else {
- System.err.println("no message integrity check");
+ // no integrity check
}
- progress.setProgress("done.", 100, 100);
+ progress.setProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ public static Bundle verifyText(Context context,
+ InputStream inStream, OutputStream outStream,
+ ProgressDialogUpdater progress)
+ throws IOException, GeneralException, PGPException, SignatureException {
+ Bundle returnData = new Bundle();
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ArmoredInputStream aIn = new ArmoredInputStream(inStream);
+
+ progress.setProgress(R.string.progress_done, 0, 100);
+
+ // mostly taken from ClearSignedFileProcessor
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, aIn);
+ byte[] lineSep = getLineSeparator();
+
+ byte[] line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+
+ while (lookAhead != -1 && aIn.isClearText()) {
+ lookAhead = readInputLine(lineOut, lookAhead, aIn);
+ line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+ }
+
+ out.close();
+
+ byte[] clearText = out.toByteArray();
+ outStream.write(clearText);
+
+ returnData.putBoolean("signature", true);
+
+ progress.setProgress(R.string.progress_processingSignature, 60, 100);
+ PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
+
+ PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
+ if (sigList == null) {
+ throw new GeneralException(context.getString(R.string.error_corruptData));
+ }
+ PGPSignature signature = null;
+ long signatureKeyId = 0;
+ PGPPublicKey signatureKey = null;
+ for (int i = 0; i < sigList.size(); ++i) {
+ signature = sigList.get(i);
+ signatureKey = findPublicKey(signature.getKeyID());
+ if (signatureKeyId == 0) {
+ signatureKeyId = signature.getKeyID();
+ }
+ if (signatureKey == null) {
+ signature = null;
+ } else {
+ signatureKeyId = signature.getKeyID();
+ String userId = null;
+ PGPPublicKeyRing sigKeyRing = findPublicKeyRing(signatureKeyId);
+ if (sigKeyRing != null) {
+ userId = getMainUserId(getMasterKey(sigKeyRing));
+ }
+ returnData.putString("signatureUserId", userId);
+ break;
+ }
+ }
+
+ returnData.putLong("signatureKeyId", signatureKeyId);
+
+ if (signature == null) {
+ returnData.putBoolean("signatureUnknown", true);
+ progress.setProgress(R.string.progress_done, 100, 100);
+ return returnData;
+ }
+
+ signature.initVerify(signatureKey, new BouncyCastleProvider());
+
+ InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
+
+ lookAhead = readInputLine(lineOut, sigIn);
+
+ processLine(signature, lineOut.toByteArray());
+
+ if (lookAhead != -1) {
+ do {
+ lookAhead = readInputLine(lineOut, lookAhead, sigIn);
+
+ signature.update((byte)'\r');
+ signature.update((byte)'\n');
+
+ processLine(signature, lineOut.toByteArray());
+ }
+ while (lookAhead != -1);
+ }
+
+ returnData.putBoolean("signatureSuccess", signature.verify());
+
+ progress.setProgress(R.string.progress_done, 100, 100);
return returnData;
}
@@ -1493,4 +1842,115 @@ public class Apg { public static Vector<PGPSecretKeyRing> getSecretKeyRings() {
return mSecretKeyRings;
}
+
+
+ // taken from ClearSignedFileProcessor in BC
+ private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int lookAhead = -1;
+ int ch;
+
+ while ((ch = fIn.read()) >= 0) {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+
+ return lookAhead;
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int ch = lookAhead;
+
+ do {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+ while ((ch = fIn.read()) >= 0);
+
+ if (ch < 0) {
+ lookAhead = -1;
+ }
+
+ return lookAhead;
+ }
+
+ private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
+ throws IOException {
+ int lookAhead = fIn.read();
+
+ if (lastCh == '\r' && lookAhead == '\n') {
+ bOut.write(lookAhead);
+ lookAhead = fIn.read();
+ }
+
+ return lookAhead;
+ }
+
+ private static void processLine(PGPSignature sig, byte[] line)
+ throws SignatureException, IOException {
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0) {
+ sig.update(line, 0, length);
+ }
+ }
+
+ private static void processLine(OutputStream aOut, PGPSignatureGenerator sGen, byte[] line)
+ throws SignatureException, IOException {
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0) {
+ sGen.update(line, 0, length);
+ }
+
+ aOut.write(line, 0, line.length);
+ }
+
+ private static int getLengthWithoutSeparator(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isLineEnding(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isLineEnding(byte b) {
+ return b == '\r' || b == '\n';
+ }
+
+ private static int getLengthWithoutWhiteSpace(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isWhiteSpace(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isWhiteSpace(byte b) {
+ return b == '\r' || b == '\n' || b == '\t' || b == ' ';
+ }
+
+ private static byte[] getLineSeparator() {
+ String nl = System.getProperty("line.separator");
+ byte[] nlBytes = new byte[nl.length()];
+
+ for (int i = 0; i != nlBytes.length; i++) {
+ nlBytes[i] = (byte)nl.charAt(i);
+ }
+
+ return nlBytes;
+ }
}
diff --git a/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java b/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java index ed1c16833..67aad7529 100644 --- a/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java +++ b/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java @@ -23,93 +23,77 @@ import org.bouncycastle2.openpgp.PGPSecretKey; import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.content.Context;
import android.content.DialogInterface;
-import android.text.InputType;
-import android.text.method.PasswordTransformationMethod;
-import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnKeyListener;
-import android.view.ViewGroup.LayoutParams;
import android.widget.EditText;
-import android.widget.LinearLayout;
import android.widget.Toast;
public class AskForSecretKeyPassPhrase {
- public static final int DIALOG_PASS_PHRASE = 12345;
-
public static interface PassPhraseCallbackInterface {
- void passPhraseCallback(String passPhrase);
+ void passPhraseCallback(long keyId, String passPhrase);
}
public static Dialog createDialog(Activity context, long secretKeyId,
PassPhraseCallbackInterface callback) {
AlertDialog.Builder alert = new AlertDialog.Builder(context);
- final PGPSecretKey secretKey =
- Apg.getMasterKey(Apg.findSecretKeyRing(secretKeyId));
- if (secretKey == null) {
- return null;
- }
-
- String userId = Apg.getMainUserIdSafe(context, secretKey);
-
alert.setTitle(R.string.title_authentification);
- alert.setMessage("Pass phrase for " + userId);
- final EditText input = new EditText(context);
- input.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
- input.setTransformationMethod(new PasswordTransformationMethod());
- input.setOnKeyListener(new OnKeyListener() {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // If the event is a key-down event on the "enter" button
- if (event.getAction() == KeyEvent.ACTION_DOWN &&
- keyCode == KeyEvent.KEYCODE_ENTER) {
- try {
- ((AlertDialog) v.getParent()).getButton(AlertDialog.BUTTON_POSITIVE)
- .performClick();
- } catch (ClassCastException e) {
- // don't do anything if we're not in that dialog
- }
- return true;
- }
- return false;
+ final PGPSecretKey secretKey;
+
+ if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
+ secretKey = null;
+ alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
+ } else {
+ secretKey = Apg.getMasterKey(Apg.findSecretKeyRing(secretKeyId));
+ if (secretKey == null) {
+ return null;
}
- });
- // 5dip padding
- int padding = (int) (10 * context.getResources().getDisplayMetrics().densityDpi / 160);
- LinearLayout layout = new LinearLayout(context);
- layout.setPadding(padding, 0, padding, 0);
- layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
- LayoutParams.WRAP_CONTENT));
- input.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
- LayoutParams.WRAP_CONTENT));
- layout.addView(input);
- alert.setView(layout);
+ String userId = Apg.getMainUserIdSafe(context, secretKey);
+ alert.setMessage(context.getString(R.string.passPhraseFor, userId));
+ }
+
+ LayoutInflater inflater =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View view = inflater.inflate(R.layout.pass_phrase, null);
+ final EditText input = (EditText) view.findViewById(R.id.passPhrase);
+ final EditText inputNotUsed = (EditText) view.findViewById(R.id.passPhraseAgain);
+ inputNotUsed.setVisibility(View.GONE);
+
+ alert.setView(view);
final PassPhraseCallbackInterface cb = callback;
final Activity activity = context;
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- activity.removeDialog(DIALOG_PASS_PHRASE);
+ activity.removeDialog(Id.dialog.pass_phrase);
String passPhrase = "" + input.getText();
- try {
- secretKey.extractPrivateKey(passPhrase.toCharArray(),
- new BouncyCastleProvider());
- } catch (PGPException e) {
- Toast.makeText(activity,
- R.string.wrong_pass_phrase,
- Toast.LENGTH_SHORT).show();
- return;
+ long keyId;
+ if (secretKey != null) {
+ try {
+ secretKey.extractPrivateKey(passPhrase.toCharArray(),
+ new BouncyCastleProvider());
+ } catch (PGPException e) {
+ Toast.makeText(activity,
+ R.string.wrongPassPhrase,
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+ keyId = secretKey.getKeyID();
+ } else {
+ keyId = Id.key.symmetric;
}
- cb.passPhraseCallback(passPhrase);
+ cb.passPhraseCallback(keyId, passPhrase);
}
});
alert.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- activity.removeDialog(DIALOG_PASS_PHRASE);
+ activity.removeDialog(Id.dialog.pass_phrase);
}
});
diff --git a/src/org/thialfihar/android/apg/BaseActivity.java b/src/org/thialfihar/android/apg/BaseActivity.java new file mode 100644 index 000000000..64705ba1f --- /dev/null +++ b/src/org/thialfihar/android/apg/BaseActivity.java @@ -0,0 +1,467 @@ +/*
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thialfihar.android.apg;
+
+import java.io.File;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.bouncycastle2.bcpg.CompressionAlgorithmTags;
+import org.bouncycastle2.bcpg.HashAlgorithmTags;
+import org.bouncycastle2.openpgp.PGPEncryptedData;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class BaseActivity extends Activity
+ implements Runnable, ProgressDialogUpdater,
+ AskForSecretKeyPassPhrase.PassPhraseCallbackInterface {
+
+ private ProgressDialog mProgressDialog = null;
+ private Thread mRunningThread = null;
+
+ private long mSecretKeyId = 0;
+ private String mDeleteFile = null;
+ protected static SharedPreferences mPreferences = null;
+
+ private static Timer mCacheTimer = new Timer();
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ handlerCallback(msg);
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (mPreferences == null) {
+ mPreferences = getPreferences(MODE_PRIVATE);
+ }
+ Apg.initialize(this);
+ if (mCacheTimer == null) {
+ setPassPhraseCacheTimer();
+ }
+ }
+
+ private void setPassPhraseCacheTimer() {
+ if (mCacheTimer != null) {
+ mCacheTimer.cancel();
+ mCacheTimer = null;
+ }
+ int ttl = getPassPhraseCacheTtl();
+ if (ttl == 0) {
+ // no timer needed
+ return;
+ }
+ // check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15),
+ // and makes sure the longest a pass phrase survives int the cache is 1.5 * ttl
+ mCacheTimer = new Timer();
+ mCacheTimer.scheduleAtFixedRate(new TimerTask() {
+ public void run() {
+ Apg.cleanUpCache(BaseActivity.this.getPassPhraseCacheTtl());
+ }
+ }, 0, ttl * 1000 / 2);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, Id.menu.option.preferences, 0, R.string.menu_preferences)
+ .setIcon(android.R.drawable.ic_menu_preferences);
+ menu.add(0, Id.menu.option.about, 1, R.string.menu_about)
+ .setIcon(android.R.drawable.ic_menu_info_details);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case Id.menu.option.about: {
+ showDialog(Id.dialog.about);
+ return true;
+ }
+
+ case Id.menu.option.preferences: {
+ startActivity(new Intent(this, PreferencesActivity.class));
+ return true;
+ }
+
+ default: {
+ break;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ // in case it is a progress dialog
+ mProgressDialog = new ProgressDialog(this);
+ mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ mProgressDialog.setCancelable(false);
+ switch (id) {
+ case Id.dialog.encrypting: {
+ mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
+ return mProgressDialog;
+ }
+
+ case Id.dialog.decrypting: {
+ mProgressDialog.setMessage(this.getString(R.string.progress_initializing));
+ return mProgressDialog;
+ }
+
+ case Id.dialog.saving: {
+ mProgressDialog.setMessage(this.getString(R.string.progress_saving));
+ return mProgressDialog;
+ }
+
+ case Id.dialog.importing: {
+ mProgressDialog.setMessage(this.getString(R.string.progress_importing));
+ return mProgressDialog;
+ }
+
+ case Id.dialog.exporting: {
+ mProgressDialog.setMessage(this.getString(R.string.progress_exporting));
+ return mProgressDialog;
+ }
+
+ default: {
+ break;
+ }
+ }
+ mProgressDialog = null;
+
+ switch (id) {
+ case Id.dialog.about: {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+
+ alert.setTitle("About " + Apg.FULL_VERSION);
+
+ LayoutInflater inflater =
+ (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View layout = inflater.inflate(R.layout.info, null);
+ TextView message = (TextView) layout.findViewById(R.id.message);
+ message.setText("This is an attempt to bring OpenPGP to Android. " +
+ "It is far from complete, but more features are planned (see website).\n\n" +
+ "Feel free to send bug reports, suggestions, feature requests, feedback, " +
+ "photographs.\n\n" +
+ "mail: thi@thialfihar.org\n" +
+ "site: http://apg.thialfihar.org\n\n" +
+ "This software is provided \"as is\", without warranty of any kind.");
+ alert.setView(layout);
+
+ alert.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ BaseActivity.this.removeDialog(Id.dialog.about);
+ }
+ });
+
+ return alert.create();
+ }
+
+ case Id.dialog.pass_phrase: {
+ return AskForSecretKeyPassPhrase.createDialog(this, getSecretKeyId(), this);
+ }
+
+ case Id.dialog.pass_phrases_do_not_match: {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+
+ alert.setIcon(android.R.drawable.ic_dialog_alert);
+ alert.setTitle(R.string.error);
+ alert.setMessage(R.string.passPhrasesDoNotMatch);
+
+ alert.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ removeDialog(Id.dialog.pass_phrases_do_not_match);
+ }
+ });
+ alert.setCancelable(false);
+
+ return alert.create();
+ }
+
+ case Id.dialog.no_pass_phrase: {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+
+ alert.setIcon(android.R.drawable.ic_dialog_alert);
+ alert.setTitle(R.string.error);
+ alert.setMessage(R.string.passPhraseMustNotBeEmpty);
+
+ alert.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ removeDialog(Id.dialog.no_pass_phrase);
+ }
+ });
+ alert.setCancelable(false);
+
+ return alert.create();
+ }
+
+ case Id.dialog.delete_file: {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+
+ alert.setIcon(android.R.drawable.ic_dialog_alert);
+ alert.setTitle(R.string.warning);
+ alert.setMessage(this.getString(R.string.fileDeleteConfirmation, getDeleteFile()));
+
+ alert.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ removeDialog(Id.dialog.delete_file);
+ File file = new File(getDeleteFile());
+ String msg = "";
+ if (file.delete()) {
+ msg = BaseActivity.this.getString(
+ R.string.fileDeleteSuccessful);
+ } else {
+ msg = BaseActivity.this.getString(
+ R.string.errorMessage,
+ BaseActivity.this.getString(
+ R.string.error_fileDeleteFailed, file));
+ }
+ Toast.makeText(BaseActivity.this,
+ msg, Toast.LENGTH_SHORT).show();
+ }
+ });
+ alert.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ removeDialog(Id.dialog.delete_file);
+ }
+ });
+ alert.setCancelable(true);
+
+ return alert.create();
+ }
+
+ default: {
+ break;
+ }
+ }
+
+ return super.onCreateDialog(id);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case Id.request.secret_keys: {
+ if (resultCode == RESULT_OK) {
+ Bundle bundle = data.getExtras();
+ setSecretKeyId(bundle.getLong("selectedKeyId"));
+ } else {
+ setSecretKeyId(Id.key.none);
+ }
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ public void setProgress(int resourceId, int progress, int max) {
+ setProgress(getString(resourceId), progress, max);
+ }
+
+ public void setProgress(int progress, int max) {
+ Message msg = new Message();
+ Bundle data = new Bundle();
+ data.putInt("type", Id.message.progress_update);
+ data.putInt("progress", progress);
+ data.putInt("max", max);
+ msg.setData(data);
+ mHandler.sendMessage(msg);
+ }
+
+ public void setProgress(String message, int progress, int max) {
+ Message msg = new Message();
+ Bundle data = new Bundle();
+ data.putInt("type", Id.message.progress_update);
+ data.putString("message", message);
+ data.putInt("progress", progress);
+ data.putInt("max", max);
+ msg.setData(data);
+ mHandler.sendMessage(msg);
+ }
+
+ public void handlerCallback(Message msg) {
+ Bundle data = msg.getData();
+ if (data == null) {
+ return;
+ }
+
+ int type = data.getInt("type");
+ switch (type) {
+ case Id.message.progress_update: {
+ String message = data.getString("message");
+ if (mProgressDialog != null) {
+ if (message != null) {
+ mProgressDialog.setMessage(message);
+ }
+ mProgressDialog.setMax(data.getInt("max"));
+ mProgressDialog.setProgress(data.getInt("progress"));
+ }
+ break;
+ }
+
+ case Id.message.import_done: // intentionall no break
+ case Id.message.export_done: // intentionall no break
+ case Id.message.done: {
+ mProgressDialog = null;
+ doneCallback(msg);
+ break;
+ }
+ }
+ }
+
+ public void doneCallback(Message msg) {
+
+ }
+
+ public void passPhraseCallback(long keyId, String passPhrase) {
+ Apg.setCachedPassPhrase(keyId, passPhrase);
+ }
+
+ public void sendMessage(Message msg) {
+ mHandler.sendMessage(msg);
+ }
+
+ public void startThread() {
+ mRunningThread = new Thread(this);
+ mRunningThread.start();
+ }
+
+ public void run() {
+
+ }
+
+ public void setSecretKeyId(long id) {
+ mSecretKeyId = id;
+ }
+
+ public long getSecretKeyId() {
+ return mSecretKeyId;
+ }
+
+ public int getPassPhraseCacheTtl() {
+ return mPreferences.getInt(Constants.pref.pass_phrase_cache_ttl, 300);
+ }
+
+ public void setPassPhraseCacheTtl(int value) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putInt(Constants.pref.pass_phrase_cache_ttl, value);
+ editor.commit();
+
+ setPassPhraseCacheTimer();
+ }
+
+ public int getDefaultEncryptionAlgorithm() {
+ return mPreferences.getInt(Constants.pref.default_encryption_algorithm,
+ PGPEncryptedData.AES_256);
+ }
+
+ public void setDefaultEncryptionAlgorithm(int value) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putInt(Constants.pref.default_encryption_algorithm, value);
+ editor.commit();
+ }
+
+ public int getDefaultHashAlgorithm() {
+ return mPreferences.getInt(Constants.pref.default_hash_algorithm,
+ HashAlgorithmTags.SHA256);
+ }
+
+ public void setDefaultHashAlgorithm(int value) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putInt(Constants.pref.default_hash_algorithm, value);
+ editor.commit();
+ }
+
+ public int getDefaultMessageCompression() {
+ return mPreferences.getInt(Constants.pref.default_message_compression,
+ CompressionAlgorithmTags.ZLIB);
+ }
+
+ public void setDefaultMessageCompression(int value) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putInt(Constants.pref.default_message_compression, value);
+ editor.commit();
+ }
+
+ public int getDefaultFileCompression() {
+ return mPreferences.getInt(Constants.pref.default_file_compression,
+ CompressionAlgorithmTags.ZLIB);
+ }
+
+ public void setDefaultFileCompression(int value) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putInt(Constants.pref.default_file_compression, value);
+ editor.commit();
+ }
+
+ public boolean getDefaultAsciiArmour() {
+ return mPreferences.getBoolean(Constants.pref.default_ascii_armour, false);
+ }
+
+ public void setDefaultAsciiArmour(boolean value) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putBoolean(Constants.pref.default_ascii_armour, value);
+ editor.commit();
+ }
+
+ public boolean hasSeenChangeLog() {
+ return mPreferences.getBoolean(Constants.pref.has_seen_change_log, false);
+ }
+
+ public void setHasSeenChangeLog(boolean value) {
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putBoolean(Constants.pref.has_seen_change_log, value);
+ editor.commit();
+ }
+
+ protected void setDeleteFile(String deleteFile) {
+ mDeleteFile = deleteFile;
+ }
+
+ protected String getDeleteFile() {
+ return mDeleteFile;
+ }
+}
diff --git a/src/org/thialfihar/android/apg/CachedPassPhrase.java b/src/org/thialfihar/android/apg/CachedPassPhrase.java new file mode 100644 index 000000000..e7566220e --- /dev/null +++ b/src/org/thialfihar/android/apg/CachedPassPhrase.java @@ -0,0 +1,39 @@ +package org.thialfihar.android.apg;
+
+public class CachedPassPhrase {
+ public final long timestamp;
+ public final String passPhrase;
+
+ public CachedPassPhrase(long timestamp, String passPhrase) {
+ super();
+ this.timestamp = timestamp;
+ this.passPhrase = passPhrase;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof CachedPassPhrase)) {
+ return false;
+ }
+
+ CachedPassPhrase o = (CachedPassPhrase) other;
+ if (timestamp != o.timestamp) {
+ return false;
+ }
+
+ if (passPhrase != o.passPhrase) {
+ if (passPhrase == null || o.passPhrase == null) {
+ return false;
+ }
+
+ if (!passPhrase.equals(o.passPhrase)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public String toString() {
+ return "(" + timestamp + ", *******)";
+ }
+}
diff --git a/src/org/thialfihar/android/apg/Constants.java b/src/org/thialfihar/android/apg/Constants.java new file mode 100644 index 000000000..f4a6a5066 --- /dev/null +++ b/src/org/thialfihar/android/apg/Constants.java @@ -0,0 +1,35 @@ +/*
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thialfihar.android.apg;
+
+import android.os.Environment;
+
+public final class Constants {
+ public static final class path {
+ public static final String app_dir = Environment.getExternalStorageDirectory() + "/APG";
+ }
+
+ public static final class pref {
+ public static final String has_seen_change_log = "seenChangeLogDialog" + Apg.VERSION;
+ public static final String default_encryption_algorithm = "defaultEncryptionAlgorithm";
+ public static final String default_hash_algorithm = "defaultHashAlgorithm";
+ public static final String default_ascii_armour = "defaultAsciiArmour";
+ public static final String default_message_compression = "defaultMessageCompression";
+ public static final String default_file_compression = "defaultFileCompression";
+ public static final String pass_phrase_cache_ttl = "passPhraseCacheTtl";
+ }
+}
diff --git a/src/org/thialfihar/android/apg/DecryptActivity.java b/src/org/thialfihar/android/apg/DecryptActivity.java new file mode 100644 index 000000000..80ad13d5e --- /dev/null +++ b/src/org/thialfihar/android/apg/DecryptActivity.java @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thialfihar.android.apg; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Security; +import java.security.SignatureException; +import java.util.regex.Matcher; + +import org.bouncycastle2.jce.provider.BouncyCastleProvider; +import org.bouncycastle2.openpgp.PGPException; +import org.bouncycastle2.util.Strings; +import org.openintents.intents.FileManager; + +import android.app.Dialog; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Message; +import android.text.ClipboardManager; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.animation.AnimationUtils; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ViewFlipper; + +public class DecryptActivity extends BaseActivity { + private long mSignatureKeyId = 0; + + private String mReplyTo = null; + private String mSubject = null; + private boolean mSignedOnly = false; + private boolean mAssumeSymmetricEncryption = false; + + private EditText mMessage = null; + private LinearLayout mSignatureLayout = null; + private ImageView mSignatureStatusImage = null; + private TextView mUserId = null; + private TextView mUserIdRest = null; + + private ViewFlipper mSource = null; + private TextView mSourceLabel = null; + private ImageView mSourcePrevious = null; + private ImageView mSourceNext = null; + + private Button mDecryptButton = null; + private Button mReplyButton = null; + + private int mDecryptTarget; + + private EditText mFilename = null; + private CheckBox mDeleteAfter = null; + private ImageButton mBrowse = null; + + private String mInputFilename = null; + private String mOutputFilename = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.decrypt); + + mSource = (ViewFlipper) findViewById(R.id.source); + mSourceLabel = (TextView) findViewById(R.id.sourceLabel); + mSourcePrevious = (ImageView) findViewById(R.id.sourcePrevious); + mSourceNext = (ImageView) findViewById(R.id.sourceNext); + + mSourcePrevious.setClickable(true); + mSourcePrevious.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mSource.setInAnimation(AnimationUtils.loadAnimation(DecryptActivity.this, + R.anim.push_right_in)); + mSource.setOutAnimation(AnimationUtils.loadAnimation(DecryptActivity.this, + R.anim.push_right_out)); + mSource.showPrevious(); + updateSource(); + } + }); + + mSourceNext.setClickable(true); + OnClickListener nextSourceClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + mSource.setInAnimation(AnimationUtils.loadAnimation(DecryptActivity.this, + R.anim.push_left_in)); + mSource.setOutAnimation(AnimationUtils.loadAnimation(DecryptActivity.this, + R.anim.push_left_out)); + mSource.showNext(); + updateSource(); + } + }; + mSourceNext.setOnClickListener(nextSourceClickListener); + + mSourceLabel.setClickable(true); + mSourceLabel.setOnClickListener(nextSourceClickListener); + + mMessage = (EditText) findViewById(R.id.message); + mDecryptButton = (Button) findViewById(R.id.btn_decrypt); + mReplyButton = (Button) findViewById(R.id.btn_reply); + mSignatureLayout = (LinearLayout) findViewById(R.id.signature); + mSignatureStatusImage = (ImageView) findViewById(R.id.ic_signature_status); + mUserId = (TextView) findViewById(R.id.mainUserId); + mUserIdRest = (TextView) findViewById(R.id.mainUserIdRest); + + // measure the height of the source_file view and set the message view's min height to that, + // so it fills mSource fully... bit of a hack. + View tmp = findViewById(R.id.sourceFile); + tmp.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + int height = tmp.getMeasuredHeight(); + mMessage.setMinimumHeight(height); + + mFilename = (EditText) findViewById(R.id.filename); + mBrowse = (ImageButton) findViewById(R.id.btn_browse); + mBrowse.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + openFile(); + } + }); + + mDeleteAfter = (CheckBox) findViewById(R.id.deleteAfterDecryption); + + // default: message source + mSource.setInAnimation(null); + mSource.setOutAnimation(null); + while (mSource.getCurrentView().getId() != R.id.sourceMessage) { + mSource.showNext(); + } + + Intent intent = getIntent(); + if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_VIEW)) { + Uri uri = intent.getData(); + try { + InputStream attachment = getContentResolver().openInputStream(uri); + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + byte bytes[] = new byte[1 << 16]; + int length; + while ((length = attachment.read(bytes)) > 0) { + byteOut.write(bytes, 0, length); + } + byteOut.close(); + String data = Strings.fromUTF8ByteArray(byteOut.toByteArray()); + mMessage.setText(data); + } catch (FileNotFoundException e) { + // ignore, then + } catch (IOException e) { + // ignore, then + } + } else if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SEND)) { + Bundle extras = intent.getExtras(); + if (extras == null) { + extras = new Bundle(); + } + String data = extras.getString(Intent.EXTRA_TEXT); + if (data != null) { + mMessage.setText(data); + } + mSubject = extras.getString(Intent.EXTRA_SUBJECT); + if (mSubject.startsWith("Fwd: ")) { + mSubject = mSubject.substring(5); + } + } else if (intent.getAction() != null && intent.getAction().equals(Apg.Intent.DECRYPT)) { + Bundle extras = intent.getExtras(); + if (extras == null) { + extras = new Bundle(); + } + String data = extras.getString("data"); + if (data != null) { + Matcher matcher = Apg.PGP_MESSAGE.matcher(data); + if (matcher.matches()) { + data = matcher.group(1); + // replace non breakable spaces + data = data.replaceAll("\\xa0", " "); + mMessage.setText(data); + } else { + matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data); + if (matcher.matches()) { + data = matcher.group(1); + // replace non breakable spaces + data = data.replaceAll("\\xa0", " "); + mMessage.setText(data); + mDecryptButton.setText(R.string.btn_verify); + } + } + } + mReplyTo = extras.getString("replyTo"); + mSubject = extras.getString("subject"); + } else if (intent.getAction() != null && intent.getAction().equals(Apg.Intent.DECRYPT_FILE)) { + mSource.setInAnimation(null); + mSource.setOutAnimation(null); + while (mSource.getCurrentView().getId() != R.id.sourceFile) { + mSource.showNext(); + } + } + + if (mSource.getCurrentView().getId() == R.id.sourceMessage && + mMessage.getText().length() == 0) { + ClipboardManager clip = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + String data = ""; + Matcher matcher = Apg.PGP_MESSAGE.matcher(clip.getText()); + if (!matcher.matches()) { + matcher = Apg.PGP_SIGNED_MESSAGE.matcher(clip.getText()); + } + if (matcher.matches()) { + data = matcher.group(1); + mMessage.setText(data); + Toast.makeText(this, R.string.usingClipboardContent, Toast.LENGTH_SHORT).show(); + } + } + + mSignatureLayout.setVisibility(View.GONE); + + mDecryptButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + decryptClicked(); + } + }); + + mReplyButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + replyClicked(); + } + }); + mReplyButton.setVisibility(View.INVISIBLE); + + if (mSource.getCurrentView().getId() == R.id.sourceMessage && + mMessage.getText().length() > 0) { + mDecryptButton.performClick(); + } + + updateSource(); + } + + private void openFile() { + String filename = mFilename.getText().toString(); + + Intent intent = new Intent(FileManager.ACTION_PICK_FILE); + + intent.setData(Uri.parse("file://" + filename)); + + intent.putExtra(FileManager.EXTRA_TITLE, getString(R.string.filemanager_titleDecrypt)); + intent.putExtra(FileManager.EXTRA_BUTTON_TEXT, R.string.filemanager_btnOpen); + + try { + startActivityForResult(intent, Id.request.filename); + } catch (ActivityNotFoundException e) { + // No compatible file manager was found. + Toast.makeText(this, R.string.oiFilemanagerNotInstalled, Toast.LENGTH_SHORT).show(); + } + } + + private void guessOutputFilename() { + mInputFilename = mFilename.getText().toString(); + File file = new File(mInputFilename); + String filename = file.getName(); + if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) { + filename = filename.substring(0, filename.length() - 4); + } + mOutputFilename = Constants.path.app_dir + "/" + filename; + } + + private void updateSource() { + switch (mSource.getCurrentView().getId()) { + case R.id.sourceFile: { + mSourceLabel.setText(R.string.label_file); + mDecryptButton.setText(R.string.btn_decrypt); + break; + } + + case R.id.sourceMessage: { + mSourceLabel.setText(R.string.label_message); + mDecryptButton.setText(R.string.btn_decrypt); + break; + } + + default: { + break; + } + } + } + + private void decryptClicked() { + if (mSource.getCurrentView().getId() == R.id.sourceFile) { + mDecryptTarget = Id.target.file; + } else { + mDecryptTarget = Id.target.message; + } + initiateDecryption(); + } + + private void initiateDecryption() { + if (mDecryptTarget == Id.target.file) { + String currentFilename = mFilename.getText().toString(); + if (mInputFilename == null || !mInputFilename.equals(currentFilename)) { + guessOutputFilename(); + } + + if (mInputFilename.equals("")) { + Toast.makeText(this, R.string.noFileSelected, Toast.LENGTH_SHORT).show(); + return; + } + + File file = new File(mInputFilename); + if (!file.exists() || !file.isFile()) { + Toast.makeText(this, getString(R.string.errorMessage, + getString(R.string.error_fileNotFound)), + Toast.LENGTH_SHORT).show(); + return; + } + } + + if (mDecryptTarget == Id.target.message) { + String messageData = mMessage.getText().toString(); + Matcher matcher = Apg.PGP_SIGNED_MESSAGE.matcher(messageData); + if (matcher.matches()) { + mSignedOnly = true; + decryptStart(); + return; + } + } + + // else treat it as an decrypted message/file + mSignedOnly = false; + String error = null; + try { + InputStream in; + if (mDecryptTarget == Id.target.file) { + in = new FileInputStream(mInputFilename); + } else { + in = new ByteArrayInputStream(mMessage.getText().toString().getBytes()); + } + try { + setSecretKeyId(Apg.getDecryptionKeyId(this, in)); + if (getSecretKeyId() == Id.key.none) { + throw new Apg.GeneralException(getString(R.string.error_noSecretKeyFound)); + } + mAssumeSymmetricEncryption = false; + } catch (Apg.NoAsymmetricEncryptionException e) { + setSecretKeyId(Id.key.symmetric); + // look at the file/message again to check whether there's + // symmetric encryption data in there + if (mDecryptTarget == Id.target.file) { + ((FileInputStream) in).reset(); + } else { + ((ByteArrayInputStream) in).reset(); + } + if (!Apg.hasSymmetricEncryption(this, in)) { + throw new Apg.GeneralException(getString(R.string.error_noKnownEncryptionFound)); + } + mAssumeSymmetricEncryption = true; + } + + if (getSecretKeyId() == Id.key.symmetric || + Apg.getCachedPassPhrase(getSecretKeyId()) == null) { + showDialog(Id.dialog.pass_phrase); + } else { + if (mDecryptTarget == Id.target.file) { + askForOutputFilename(); + } else { + decryptStart(); + } + } + } catch (FileNotFoundException e) { + error = getString(R.string.error_fileNotFound); + } catch (IOException e) { + error = e.getLocalizedMessage(); + } catch (Apg.GeneralException e) { + error = e.getLocalizedMessage(); + } + if (error != null) { + Toast.makeText(this, getString(R.string.errorMessage, error), + Toast.LENGTH_SHORT).show(); + } + } + + private void replyClicked() { + Intent intent = new Intent(this, EncryptActivity.class); + intent.setAction(Apg.Intent.ENCRYPT); + String data = mMessage.getText().toString(); + data = data.replaceAll("(?m)^", "> "); + data = "\n\n" + data; + intent.putExtra("data", data); + intent.putExtra("subject", "Re: " + mSubject); + intent.putExtra("sendTo", mReplyTo); + intent.putExtra("eyId", mSignatureKeyId); + intent.putExtra("signatureKeyId", getSecretKeyId()); + intent.putExtra("encryptionKeyIds", new long[] { mSignatureKeyId }); + startActivity(intent); + } + + private void askForOutputFilename() { + showDialog(Id.dialog.output_filename); + } + + @Override + public void passPhraseCallback(long keyId, String passPhrase) { + super.passPhraseCallback(keyId, passPhrase); + if (mDecryptTarget == Id.target.file) { + askForOutputFilename(); + } else { + decryptStart(); + } + } + + private void decryptStart() { + showDialog(Id.dialog.decrypting); + startThread(); + } + + @Override + public void run() { + String error = null; + Security.addProvider(new BouncyCastleProvider()); + + Bundle data = new Bundle(); + Message msg = new Message(); + + try { + PositionAwareInputStream in = null; + OutputStream out = null; + long size = 0; + + if (mDecryptTarget == Id.target.message) { + String messageData = mMessage.getText().toString(); + in = new PositionAwareInputStream(new ByteArrayInputStream(messageData.getBytes())); + out = new ByteArrayOutputStream(); + size = messageData.getBytes().length; + } else { + in = new PositionAwareInputStream(new FileInputStream(mInputFilename)); + out = new FileOutputStream(mOutputFilename); + File file = new File(mInputFilename); + size = file.length(); + } + + if (mSignedOnly) { + data = Apg.verifyText(this, in, out, this); + } else { + data = Apg.decrypt(this, in, out, size, Apg.getCachedPassPhrase(getSecretKeyId()), + this, mAssumeSymmetricEncryption); + } + + out.close(); + if (mDecryptTarget == Id.target.message) { + data.putString("decryptedMessage", + Strings.fromUTF8ByteArray(((ByteArrayOutputStream) + out).toByteArray())); + } + } catch (PGPException e) { + error = e.getMessage(); + } catch (IOException e) { + error = e.getMessage(); + } catch (SignatureException e) { + error = e.getMessage(); + e.printStackTrace(); + } catch (Apg.GeneralException e) { + error = e.getMessage(); + } + + data.putInt("type", Id.message.done); + + if (error != null) { + data.putString("error", error); + } + + msg.setData(data); + sendMessage(msg); + } + + @Override + public void doneCallback(Message msg) { + super.doneCallback(msg); + + Bundle data = msg.getData(); + removeDialog(Id.dialog.decrypting); + mSignatureKeyId = 0; + mSignatureLayout.setVisibility(View.GONE); + mReplyButton.setVisibility(View.INVISIBLE); + + String error = data.getString("error"); + if (error != null) { + Toast.makeText(DecryptActivity.this, + getString(R.string.errorMessage, + data.getString("error")), + Toast.LENGTH_SHORT).show(); + return; + } + + Toast.makeText(this, R.string.decryptionSuccessful, Toast.LENGTH_SHORT).show(); + switch (mDecryptTarget) { + case Id.target.message: { + String decryptedMessage = data.getString("decryptedMessage"); + mMessage.setText(decryptedMessage); + mReplyButton.setVisibility(View.VISIBLE); + break; + } + + case Id.target.file: { + if (mDeleteAfter.isChecked()) { + setDeleteFile(mInputFilename); + showDialog(Id.dialog.delete_file); + } + break; + } + + default: { + // shouldn't happen + break; + } + } + + if (data.getBoolean("signature")) { + String userId = data.getString("signatureUserId"); + mSignatureKeyId = data.getLong("signatureKeyId"); + mUserIdRest.setText("id: " + Long.toHexString(mSignatureKeyId & 0xffffffffL)); + if (userId == null) { + userId = getResources().getString(R.string.unknownUserId); + } + String chunks[] = userId.split(" <", 2); + userId = chunks[0]; + if (chunks.length > 1) { + mUserIdRest.setText("<" + chunks[1]); + } + mUserId.setText(userId); + + if (data.getBoolean("signatureSuccess")) { + mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); + } else if (data.getBoolean("signatureUnknown")) { + mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + } else { + mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + } + mSignatureLayout.setVisibility(View.VISIBLE); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case Id.request.filename: { + if (resultCode == RESULT_OK && data != null) { + String filename = data.getDataString(); + if (filename != null) { + // Get rid of URI prefix: + if (filename.startsWith("file://")) { + filename = filename.substring(7); + } + // replace %20 and so on + filename = Uri.decode(filename); + + mFilename.setText(filename); + } + } + return; + } + + case Id.request.output_filename: { + if (resultCode == RESULT_OK && data != null) { + String filename = data.getDataString(); + if (filename != null) { + // Get rid of URI prefix: + if (filename.startsWith("file://")) { + filename = filename.substring(7); + } + // replace %20 and so on + filename = Uri.decode(filename); + + FileDialog.setFilename(filename); + } + } + return; + } + + default: { + break; + } + } + + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected Dialog onCreateDialog(int id) { + switch (id) { + case Id.dialog.output_filename: { + return FileDialog.build(this, getString(R.string.title_decryptToFile), + getString(R.string.specifyFileToDecryptTo), + mOutputFilename, + new FileDialog.OnClickListener() { + + @Override + public void onOkClick(String filename) { + removeDialog(Id.dialog.output_filename); + mOutputFilename = filename; + decryptStart(); + } + + @Override + public void onCancelClick() { + removeDialog(Id.dialog.output_filename); + } + }, + getString(R.string.filemanager_titleSave), + getString(R.string.filemanager_btnSave), + Id.request.output_filename); + } + + default: { + break; + } + } + + return super.onCreateDialog(id); + } +} diff --git a/src/org/thialfihar/android/apg/DecryptMessageActivity.java b/src/org/thialfihar/android/apg/DecryptMessageActivity.java deleted file mode 100644 index 179d5be55..000000000 --- a/src/org/thialfihar/android/apg/DecryptMessageActivity.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.thialfihar.android.apg; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.security.Security; -import java.security.SignatureException; -import java.util.regex.Matcher; - -import org.bouncycastle2.jce.provider.BouncyCastleProvider; -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.util.Strings; - -import android.app.Activity; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.text.ClipboardManager; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -public class DecryptMessageActivity extends Activity - implements Runnable, ProgressDialogUpdater, - AskForSecretKeyPassPhrase.PassPhraseCallbackInterface { - static final int GET_PUCLIC_KEYS = 1; - static final int GET_SECRET_KEY = 2; - - static final int DIALOG_DECRYPTING = 1; - - static final int MESSAGE_PROGRESS_UPDATE = 1; - static final int MESSAGE_DONE = 2; - - private long mDecryptionKeyId = 0; - private long mSignatureKeyId = 0; - - private String mReplyTo = null; - private String mSubject = null; - - private ProgressDialog mProgressDialog = null; - private Thread mRunningThread = null; - - private EditText mMessage = null; - private LinearLayout mSignatureLayout = null; - private ImageView mSignatureStatusImage = null; - private TextView mUserId = null; - private TextView mUserIdRest = null; - private Button mDecryptButton = null; - - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - Bundle data = msg.getData(); - if (data != null) { - int type = data.getInt("type"); - switch (type) { - case MESSAGE_PROGRESS_UPDATE: { - String message = data.getString("message"); - if (mProgressDialog != null) { - if (message != null) { - mProgressDialog.setMessage(message); - } - mProgressDialog.setMax(data.getInt("max")); - mProgressDialog.setProgress(data.getInt("progress")); - } - break; - } - - case MESSAGE_DONE: { - removeDialog(DIALOG_DECRYPTING); - mProgressDialog = null; - mSignatureKeyId = 0; - String error = data.getString("error"); - String decryptedMessage = data.getString("decryptedMessage"); - if (error != null) { - Toast.makeText(DecryptMessageActivity.this, - "Error: " + data.getString("error"), - Toast.LENGTH_SHORT).show(); - } - mSignatureLayout.setVisibility(View.INVISIBLE); - if (decryptedMessage != null) { - mMessage.setText(decryptedMessage); - mDecryptButton.setText(R.string.btn_reply); - mDecryptButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - replyClicked(); - } - }); - - if (data.getBoolean("signature")) { - String userId = data.getString("signatureUserId"); - mSignatureKeyId = data.getLong("signatureKeyId"); - mUserIdRest.setText("id: " + - Long.toHexString(mSignatureKeyId & 0xffffffffL)); - if (userId == null) { - userId = - getResources() - .getString( - R.string.unknown_user_id); - } - String chunks[] = userId.split(" <", 2); - userId = chunks[0]; - if (chunks.length > 1) { - mUserIdRest.setText("<" + chunks[1]); - } - mUserId.setText(userId); - - if (data.getBoolean("signatureSuccess")) { - mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); - } else if (data.getBoolean("signatureUnknown")) { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - } else { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - } - mSignatureLayout.setVisibility(View.VISIBLE); - } - } - - break; - } - } - } - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.decrypt_message); - - Apg.initialize(this); - - mMessage = (EditText) findViewById(R.id.message); - mDecryptButton = (Button) findViewById(R.id.btn_decrypt); - mSignatureLayout = (LinearLayout) findViewById(R.id.layout_signature); - mSignatureStatusImage = (ImageView) findViewById(R.id.ic_signature_status); - mUserId = (TextView) findViewById(R.id.main_user_id); - mUserIdRest = (TextView) findViewById(R.id.main_user_id_rest); - - Intent intent = getIntent(); - if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_VIEW)) { - Uri uri = intent.getData(); - try { - InputStream attachment = getContentResolver().openInputStream(uri); - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - byte bytes[] = new byte[1 << 16]; - int length; - while ((length = attachment.read(bytes)) > 0) { - byteOut.write(bytes, 0, length); - } - byteOut.close(); - String data = Strings.fromUTF8ByteArray(byteOut.toByteArray()); - mMessage.setText(data); - } catch (FileNotFoundException e) { - // ignore, then - } catch (IOException e) { - // ignore, then - } - } else if (intent.getAction() != null && intent.getAction().equals(Apg.Intent.DECRYPT)) { - String data = intent.getExtras().getString("data"); - if (data != null) { - Matcher matcher = Apg.PGP_MESSAGE.matcher(data); - if (matcher.matches()) { - data = matcher.group(1); - mMessage.setText(data); - } - } - mReplyTo = intent.getExtras().getString("replyTo"); - mSubject = intent.getExtras().getString("subject"); - } else { - ClipboardManager clip = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); - String data = ""; - Matcher matcher = Apg.PGP_MESSAGE.matcher(clip.getText()); - if (matcher.matches()) { - data = matcher.group(1); - mMessage.setText(data); - Toast.makeText(this, R.string.using_clipboard_content, Toast.LENGTH_SHORT).show(); - } - } - - mSignatureLayout.setVisibility(View.INVISIBLE); - - mDecryptButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - decryptClicked(); - } - }); - - if (mMessage.getText().length() > 0) { - mDecryptButton.performClick(); - } - } - - @Override - protected Dialog onCreateDialog(int id) { - switch (id) { - case DIALOG_DECRYPTING: { - mProgressDialog = new ProgressDialog(this); - mProgressDialog.setMessage("initializing..."); - mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - mProgressDialog.setCancelable(false); - return mProgressDialog; - } - - case AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE: { - return AskForSecretKeyPassPhrase.createDialog(this, mDecryptionKeyId, this); - } - } - - return super.onCreateDialog(id); - } - - @Override - public void setProgress(int progress, int max) { - Message msg = new Message(); - Bundle data = new Bundle(); - data.putInt("type", MESSAGE_PROGRESS_UPDATE); - data.putInt("progress", progress); - data.putInt("max", max); - msg.setData(data); - mHandler.sendMessage(msg); - } - - @Override - public void setProgress(String message, int progress, int max) { - Message msg = new Message(); - Bundle data = new Bundle(); - data.putInt("type", MESSAGE_PROGRESS_UPDATE); - data.putString("message", message); - data.putInt("progress", progress); - data.putInt("max", max); - msg.setData(data); - mHandler.sendMessage(msg); - } - - private void decryptClicked() { - String error = null; - ByteArrayInputStream in = - new ByteArrayInputStream(mMessage.getText().toString().getBytes()); - try { - mDecryptionKeyId = Apg.getDecryptionKeyId(in); - showDialog(AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE); - } catch (IOException e) { - error = e.getLocalizedMessage(); - } catch (Apg.GeneralException e) { - error = e.getLocalizedMessage(); - } - if (error != null) { - Toast.makeText(this, "Error: " + error, Toast.LENGTH_SHORT).show(); - } - } - - private void replyClicked() { - Intent intent = new Intent(this, EncryptMessageActivity.class); - intent.setAction(Apg.Intent.ENCRYPT); - String data = mMessage.getText().toString(); - data = data.replaceAll("(?m)^", "> "); - data = "\n\n" + data; - intent.putExtra("data", data); - intent.putExtra("subject", "Re: " + mSubject); - intent.putExtra("sendTo", mReplyTo); - intent.putExtra("eyId", mSignatureKeyId); - intent.putExtra("signatureKeyId", mDecryptionKeyId); - intent.putExtra("encryptionKeyIds", new long[] { mSignatureKeyId }); - startActivity(intent); - } - - public void passPhraseCallback(String passPhrase) { - Apg.setPassPhrase(passPhrase); - decryptStart(); - } - - private void decryptStart() { - showDialog(DIALOG_DECRYPTING); - mRunningThread = new Thread(this); - mRunningThread.start(); - } - - public void run() { - String error = null; - Security.addProvider(new BouncyCastleProvider()); - - Bundle data = new Bundle(); - Message msg = new Message(); - - ByteArrayInputStream in = - new ByteArrayInputStream(mMessage.getText().toString().getBytes()); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - try { - data = Apg.decrypt(in, out, Apg.getPassPhrase(), this); - } catch (PGPException e) { - error = e.getMessage(); - } catch (IOException e) { - error = e.getMessage(); - } catch (SignatureException e) { - error = e.getMessage(); - e.printStackTrace(); - } catch (Apg.GeneralException e) { - error = e.getMessage(); - } - - data.putInt("type", MESSAGE_DONE); - - if (error != null) { - data.putString("error", error); - } else { - data.putString("decryptedMessage", Strings.fromUTF8ByteArray(out.toByteArray())); - } - - msg.setData(data); - mHandler.sendMessage(msg); - } -} diff --git a/src/org/thialfihar/android/apg/EditKeyActivity.java b/src/org/thialfihar/android/apg/EditKeyActivity.java index b5b7045b7..b1e37e8a1 100644 --- a/src/org/thialfihar/android/apg/EditKeyActivity.java +++ b/src/org/thialfihar/android/apg/EditKeyActivity.java @@ -24,43 +24,28 @@ import java.util.Vector; import org.bouncycastle2.openpgp.PGPException; import org.bouncycastle2.openpgp.PGPSecretKey; import org.bouncycastle2.openpgp.PGPSecretKeyRing; +import org.thialfihar.android.apg.ui.widget.KeyEditor; import org.thialfihar.android.apg.ui.widget.SectionView; import org.thialfihar.android.apg.utils.IterableIterator; -import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; -import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; -import android.os.Handler; import android.os.Message; -import android.text.InputType; -import android.text.method.PasswordTransformationMethod; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; -import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.Toast; -public class EditKeyActivity extends Activity - implements OnClickListener, ProgressDialogUpdater, Runnable { - static final int OPTION_MENU_NEW_PASS_PHRASE = 1; - - static final int DIALOG_NEW_PASS_PHRASE = 1; - static final int DIALOG_PASS_PHRASES_DO_NOT_MATCH = 2; - static final int DIALOG_NO_PASS_PHRASE = 3; - static final int DIALOG_SAVING = 4; - - static final int MESSAGE_PROGRESS_UPDATE = 1; - static final int MESSAGE_DONE = 2; +public class EditKeyActivity extends BaseActivity implements OnClickListener { private PGPSecretKeyRing mKeyRing = null; @@ -70,56 +55,9 @@ public class EditKeyActivity extends Activity private Button mSaveButton; private Button mDiscardButton; - private ProgressDialog mProgressDialog = null; - private Thread mRunningThread = null; - + private String mCurrentPassPhrase = null; private String mNewPassPhrase = null; - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - Bundle data = msg.getData(); - if (data != null) { - int type = data.getInt("type"); - switch (type) { - case MESSAGE_PROGRESS_UPDATE: { - String message = data.getString("message"); - if (mProgressDialog != null) { - if (message != null) { - mProgressDialog.setMessage(message); - } - mProgressDialog.setMax(data.getInt("max")); - mProgressDialog.setProgress(data.getInt("progress")); - } - break; - } - - case MESSAGE_DONE: { - removeDialog(DIALOG_SAVING); - mProgressDialog = null; - - String error = data.getString("error"); - if (error != null) { - Toast.makeText(EditKeyActivity.this, - "Error: " + data.getString("error"), - Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(EditKeyActivity.this, R.string.key_saved, - Toast.LENGTH_SHORT).show(); - setResult(RESULT_OK); - finish(); - } - break; - } - - default: { - break; - } - } - } - } - }; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -133,6 +71,7 @@ public class EditKeyActivity extends Activity if (intent.getExtras() != null) { keyId = intent.getExtras().getLong("keyId"); } + if (keyId != 0) { PGPSecretKey masterKey = null; mKeyRing = Apg.getSecretKeyRing(keyId); @@ -149,10 +88,6 @@ public class EditKeyActivity extends Activity } } - if (Apg.getPassPhrase() == null) { - Apg.setPassPhrase(""); - } - mSaveButton = (Button) findViewById(R.id.btn_save); mDiscardButton = (Button) findViewById(R.id.btn_discard); @@ -164,105 +99,95 @@ public class EditKeyActivity extends Activity LinearLayout container = (LinearLayout) findViewById(R.id.container); mUserIds = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); - mUserIds.setType(SectionView.TYPE_USER_ID); + mUserIds.setType(Id.type.user_id); mUserIds.setUserIds(userIds); container.addView(mUserIds); mKeys = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); - mKeys.setType(SectionView.TYPE_KEY); + mKeys.setType(Id.type.key); mKeys.setKeys(keys); container.addView(mKeys); + mCurrentPassPhrase = Apg.getEditPassPhrase(); + if (mCurrentPassPhrase == null) { + mCurrentPassPhrase = ""; + } + Toast.makeText(this, "Warning: Key editing is still kind of beta.", Toast.LENGTH_LONG).show(); } + public long getMasterKeyId() { + if (mKeys.getEditors().getChildCount() == 0) { + return 0; + } + return ((KeyEditor) mKeys.getEditors().getChildAt(0)).getValue().getKeyID(); + } + public boolean havePassPhrase() { - return (Apg.getPassPhrase() != null && !Apg.getPassPhrase().equals("")) || - (mNewPassPhrase != null && mNewPassPhrase.equals("")); + return (!mCurrentPassPhrase.equals("")) || + (mNewPassPhrase != null && !mNewPassPhrase.equals("")); } @Override public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, OPTION_MENU_NEW_PASS_PHRASE, 0, - (havePassPhrase() ? "Change Pass Phrase" : "Set Pass Phrase")) + menu.add(0, Id.menu.option.new_pass_phrase, 0, + (havePassPhrase() ? R.string.menu_changePassPhrase : R.string.menu_setPassPhrase)) .setIcon(android.R.drawable.ic_menu_add); + menu.add(0, Id.menu.option.preferences, 1, R.string.menu_preferences) + .setIcon(android.R.drawable.ic_menu_preferences); + menu.add(0, Id.menu.option.about, 2, R.string.menu_about) + .setIcon(android.R.drawable.ic_menu_info_details); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case OPTION_MENU_NEW_PASS_PHRASE: { - showDialog(DIALOG_NEW_PASS_PHRASE); + case Id.menu.option.new_pass_phrase: { + showDialog(Id.dialog.new_pass_phrase); return true; } default: { - break; + return super.onOptionsItemSelected(item); } } - return false; } @Override protected Dialog onCreateDialog(int id) { switch (id) { - case DIALOG_SAVING: { - mProgressDialog = new ProgressDialog(this); - mProgressDialog.setMessage("saving..."); - mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - mProgressDialog.setCancelable(false); - return mProgressDialog; - } - - case DIALOG_NEW_PASS_PHRASE: { + case Id.dialog.new_pass_phrase: { AlertDialog.Builder alert = new AlertDialog.Builder(this); if (havePassPhrase()) { - alert.setTitle("Change Pass Phrase"); + alert.setTitle(R.string.title_changePassPhrase); } else { - alert.setTitle("Set Pass Phrase"); + alert.setTitle(R.string.title_setPassPhrase); } - alert.setMessage("Enter the pass phrase twice."); - - final EditText input1 = new EditText(this); - final EditText input2 = new EditText(this); - input1.setText(""); - input2.setText(""); - input1.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD); - input2.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD); - input1.setTransformationMethod(new PasswordTransformationMethod()); - input2.setTransformationMethod(new PasswordTransformationMethod()); - - // 5dip padding - int padding = (int) (10 * getResources().getDisplayMetrics().densityDpi / 160); - LinearLayout layout = new LinearLayout(this); - layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(padding, 0, padding, 0); - layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.WRAP_CONTENT)); - input1.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.WRAP_CONTENT)); - input2.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.WRAP_CONTENT)); - layout.addView(input1); - layout.addView(input2); - - alert.setView(layout); + alert.setMessage(R.string.enterPassPhraseTwice); + + LayoutInflater inflater = + (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflater.inflate(R.layout.pass_phrase, null); + final EditText input1 = (EditText) view.findViewById(R.id.passPhrase); + final EditText input2 = (EditText) view.findViewById(R.id.passPhraseAgain); + + alert.setView(view); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - removeDialog(DIALOG_NEW_PASS_PHRASE); + removeDialog(Id.dialog.new_pass_phrase); String passPhrase1 = "" + input1.getText(); String passPhrase2 = "" + input2.getText(); if (!passPhrase1.equals(passPhrase2)) { - showDialog(DIALOG_PASS_PHRASES_DO_NOT_MATCH); + showDialog(Id.dialog.pass_phrases_do_not_match); return; } if (passPhrase1.equals("")) { - showDialog(DIALOG_NO_PASS_PHRASE); + showDialog(Id.dialog.no_pass_phrase); return; } @@ -273,54 +198,17 @@ public class EditKeyActivity extends Activity alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - removeDialog(DIALOG_NEW_PASS_PHRASE); - } - }); - - return alert.create(); - } - - case DIALOG_PASS_PHRASES_DO_NOT_MATCH: { - AlertDialog.Builder alert = new AlertDialog.Builder(this); - - alert.setIcon(android.R.drawable.ic_dialog_alert); - alert.setTitle("Error"); - alert.setMessage("The pass phrases didn't match."); - - alert.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - removeDialog(DIALOG_PASS_PHRASES_DO_NOT_MATCH); - } - }); - alert.setCancelable(false); - - return alert.create(); - } - - case DIALOG_NO_PASS_PHRASE: { - AlertDialog.Builder alert = new AlertDialog.Builder(this); - - alert.setIcon(android.R.drawable.ic_dialog_alert); - alert.setTitle("Error"); - alert.setMessage("Empty pass phrases are not supported."); - - alert.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - removeDialog(DIALOG_NO_PASS_PHRASE); + removeDialog(Id.dialog.new_pass_phrase); } }); - alert.setCancelable(false); return alert.create(); } default: { - break; + return super.onCreateDialog(id); } } - return super.onCreateDialog(id); } @Override @@ -334,23 +222,22 @@ public class EditKeyActivity extends Activity } private void saveClicked() { - if ((Apg.getPassPhrase() == null || Apg.getPassPhrase().equals("")) && - (mNewPassPhrase == null || mNewPassPhrase.equals(""))) { - Toast.makeText(this, R.string.set_a_pass_phrase, Toast.LENGTH_SHORT).show(); + if (!havePassPhrase()) { + Toast.makeText(this, R.string.setAPassPhrase, Toast.LENGTH_SHORT).show(); return; } - showDialog(DIALOG_SAVING); - mRunningThread = new Thread(this); - mRunningThread.start(); + showDialog(Id.dialog.saving); + startThread(); } + @Override public void run() { String error = null; Bundle data = new Bundle(); Message msg = new Message(); try { - String oldPassPhrase = Apg.getPassPhrase(); + String oldPassPhrase = mCurrentPassPhrase; String newPassPhrase = mNewPassPhrase; if (newPassPhrase == null) { newPassPhrase = oldPassPhrase; @@ -368,34 +255,32 @@ public class EditKeyActivity extends Activity error = e.getMessage(); } - data.putInt("type", MESSAGE_DONE); + data.putInt("type", Id.message.done); if (error != null) { data.putString("error", error); } msg.setData(data); - mHandler.sendMessage(msg); + sendMessage(msg); } - public void setProgress(int progress, int max) { - Message msg = new Message(); - Bundle data = new Bundle(); - data.putInt("type", MESSAGE_PROGRESS_UPDATE); - data.putInt("progress", progress); - data.putInt("max", max); - msg.setData(data); - mHandler.sendMessage(msg); - } + @Override + public void doneCallback(Message msg) { + super.doneCallback(msg); - public void setProgress(String message, int progress, int max) { - Message msg = new Message(); - Bundle data = new Bundle(); - data.putInt("type", MESSAGE_PROGRESS_UPDATE); - data.putString("message", message); - data.putInt("progress", progress); - data.putInt("max", max); - msg.setData(data); - mHandler.sendMessage(msg); + Bundle data = msg.getData(); + removeDialog(Id.dialog.saving); + + String error = data.getString("error"); + if (error != null) { + Toast.makeText(EditKeyActivity.this, + getString(R.string.errorMessage, data.getString("error")), + Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(EditKeyActivity.this, R.string.keySaved, Toast.LENGTH_SHORT).show(); + setResult(RESULT_OK); + finish(); + } } }
\ No newline at end of file diff --git a/src/org/thialfihar/android/apg/EncryptActivity.java b/src/org/thialfihar/android/apg/EncryptActivity.java new file mode 100644 index 000000000..073e9dc9c --- /dev/null +++ b/src/org/thialfihar/android/apg/EncryptActivity.java @@ -0,0 +1,810 @@ +/* + * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thialfihar.android.apg; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; +import java.util.Vector; + +import org.bouncycastle2.openpgp.PGPException; +import org.bouncycastle2.openpgp.PGPPublicKey; +import org.bouncycastle2.openpgp.PGPPublicKeyRing; +import org.bouncycastle2.openpgp.PGPSecretKey; +import org.bouncycastle2.openpgp.PGPSecretKeyRing; +import org.bouncycastle2.util.Strings; +import org.openintents.intents.FileManager; +import org.thialfihar.android.apg.Apg.GeneralException; +import org.thialfihar.android.apg.utils.Choice; + +import android.app.Dialog; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.Message; +import android.text.ClipboardManager; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.animation.AnimationUtils; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ViewFlipper; + +public class EncryptActivity extends BaseActivity { + private String mSubject = null; + private String mSendTo = null; + + private long mEncryptionKeyIds[] = null; + + private EditText mMessage = null; + private Button mSelectKeysButton = null; + private Button mEncryptButton = null; + private Button mEncryptToClipboardButton = null; + private CheckBox mSign = null; + private TextView mMainUserId = null; + private TextView mMainUserIdRest = null; + + private ViewFlipper mSource = null; + private TextView mSourceLabel = null; + private ImageView mSourcePrevious = null; + private ImageView mSourceNext = null; + + private ViewFlipper mMode = null; + private TextView mModeLabel = null; + private ImageView mModePrevious = null; + private ImageView mModeNext = null; + + private int mEncryptTarget; + + private EditText mPassPhrase = null; + private EditText mPassPhraseAgain = null; + private CheckBox mAsciiArmour = null; + private Spinner mFileCompression = null; + + private EditText mFilename = null; + private CheckBox mDeleteAfter = null; + private ImageButton mBrowse = null; + + private String mInputFilename = null; + private String mOutputFilename = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.encrypt); + + mSource = (ViewFlipper) findViewById(R.id.source); + mSourceLabel = (TextView) findViewById(R.id.sourceLabel); + mSourcePrevious = (ImageView) findViewById(R.id.sourcePrevious); + mSourceNext = (ImageView) findViewById(R.id.sourceNext); + + mSourcePrevious.setClickable(true); + mSourcePrevious.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mSource.setInAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_right_in)); + mSource.setOutAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_right_out)); + mSource.showPrevious(); + updateSource(); + } + }); + + mSourceNext.setClickable(true); + OnClickListener nextSourceClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + mSource.setInAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_left_in)); + mSource.setOutAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_left_out)); + mSource.showNext(); + updateSource(); + } + }; + mSourceNext.setOnClickListener(nextSourceClickListener); + + mSourceLabel.setClickable(true); + mSourceLabel.setOnClickListener(nextSourceClickListener); + + mMode = (ViewFlipper) findViewById(R.id.mode); + mModeLabel = (TextView) findViewById(R.id.modeLabel); + mModePrevious = (ImageView) findViewById(R.id.modePrevious); + mModeNext = (ImageView) findViewById(R.id.modeNext); + + mModePrevious.setClickable(true); + mModePrevious.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mMode.setInAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_right_in)); + mMode.setOutAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_right_out)); + mMode.showPrevious(); + updateMode(); + } + }); + + OnClickListener nextModeClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + mMode.setInAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_left_in)); + mMode.setOutAnimation(AnimationUtils.loadAnimation(EncryptActivity.this, + R.anim.push_left_out)); + mMode.showNext(); + updateMode(); + } + }; + mModeNext.setOnClickListener(nextModeClickListener); + + mModeLabel.setClickable(true); + mModeLabel.setOnClickListener(nextModeClickListener); + + mMessage = (EditText) findViewById(R.id.message); + mSelectKeysButton = (Button) findViewById(R.id.btn_selectEncryptKeys); + mEncryptButton = (Button) findViewById(R.id.btn_encrypt); + mEncryptToClipboardButton = (Button) findViewById(R.id.btn_encryptToClipboard); + mSign = (CheckBox) findViewById(R.id.sign); + mMainUserId = (TextView) findViewById(R.id.mainUserId); + mMainUserIdRest = (TextView) findViewById(R.id.mainUserIdRest); + + mPassPhrase = (EditText) findViewById(R.id.passPhrase); + mPassPhraseAgain = (EditText) findViewById(R.id.passPhraseAgain); + + // measure the height of the source_file view and set the message view's min height to that, + // so it fills mSource fully... bit of a hack. + View tmp = findViewById(R.id.sourceFile); + tmp.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + int height = tmp.getMeasuredHeight(); + mMessage.setMinimumHeight(height); + + mFilename = (EditText) findViewById(R.id.filename); + mBrowse = (ImageButton) findViewById(R.id.btn_browse); + mBrowse.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + openFile(); + } + }); + + mFileCompression = (Spinner) findViewById(R.id.fileCompression); + Choice[] choices = new Choice[] { + new Choice(Id.choice.compression.none, getString(R.string.choice_none)), + new Choice(Id.choice.compression.zip, "ZIP"), + new Choice(Id.choice.compression.bzip2, "BZIP2"), + new Choice(Id.choice.compression.zlib, "ZLIB"), + }; + ArrayAdapter<Choice> adapter = + new ArrayAdapter<Choice>(this, android.R.layout.simple_spinner_item, choices); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mFileCompression.setAdapter(adapter); + + int defaultFileCompression = getDefaultFileCompression(); + for (int i = 0; i < choices.length; ++i) { + if (choices[i].getId() == defaultFileCompression) { + mFileCompression.setSelection(i); + break; + } + } + + mDeleteAfter = (CheckBox) findViewById(R.id.deleteAfterEncryption); + + mAsciiArmour = (CheckBox) findViewById(R.id.asciiArmour); + mAsciiArmour.setChecked(getDefaultAsciiArmour()); + mAsciiArmour.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + guessOutputFilename(); + } + }); + + mEncryptToClipboardButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + encryptToClipboardClicked(); + } + }); + + mEncryptButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + encryptClicked(); + } + }); + + mSelectKeysButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + selectPublicKeys(); + } + }); + + mSign.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + CheckBox checkBox = (CheckBox) v; + if (checkBox.isChecked()) { + selectSecretKey(); + } else { + setSecretKeyId(Id.key.none); + updateView(); + } + } + }); + + Intent intent = getIntent(); + if (intent.getAction() != null && + (intent.getAction().equals(Apg.Intent.ENCRYPT) || + intent.getAction().equals(Apg.Intent.ENCRYPT_FILE))) { + Bundle extras = intent.getExtras(); + if (extras == null) { + extras = new Bundle(); + } + String data = extras.getString("data"); + mSendTo = extras.getString("sendTo"); + mSubject = extras.getString("subject"); + long signatureKeyId = extras.getLong("signatureKeyId"); + long encryptionKeyIds[] = extras.getLongArray("encryptionKeyIds"); + if (signatureKeyId != 0) { + PGPSecretKeyRing keyRing = Apg.findSecretKeyRing(signatureKeyId); + PGPSecretKey masterKey = null; + if (keyRing != null) { + masterKey = Apg.getMasterKey(keyRing); + if (masterKey != null) { + Vector<PGPSecretKey> signKeys = Apg.getUsableSigningKeys(keyRing); + if (signKeys.size() > 0) { + setSecretKeyId(masterKey.getKeyID()); + } + } + } + } + + if (encryptionKeyIds != null) { + Vector<Long> goodIds = new Vector<Long>(); + for (int i = 0; i < encryptionKeyIds.length; ++i) { + PGPPublicKeyRing keyRing = Apg.findPublicKeyRing(encryptionKeyIds[i]); + PGPPublicKey masterKey = null; + if (keyRing == null) { + continue; + } + masterKey = Apg.getMasterKey(keyRing); + if (masterKey == null) { + continue; + } + Vector<PGPPublicKey> encryptKeys = Apg.getUsableEncryptKeys(keyRing); + if (encryptKeys.size() == 0) { + continue; + } + goodIds.add(masterKey.getKeyID()); + } + if (goodIds.size() > 0) { + mEncryptionKeyIds = new long[goodIds.size()]; + for (int i = 0; i < goodIds.size(); ++i) { + mEncryptionKeyIds[i] = goodIds.get(i); + } + } + } + + if (intent.getAction().equals(Apg.Intent.ENCRYPT)) { + if (data != null) { + mMessage.setText(data); + } + mSource.setInAnimation(null); + mSource.setOutAnimation(null); + while (mSource.getCurrentView().getId() != R.id.sourceMessage) { + mSource.showNext(); + } + } else if (intent.getAction().equals(Apg.Intent.ENCRYPT_FILE)) { + mSource.setInAnimation(null); + mSource.setOutAnimation(null); + while (mSource.getCurrentView().getId() != R.id.sourceFile) { + mSource.showNext(); + } + } + } + + updateView(); + updateSource(); + updateMode(); + } + + private void openFile() { + String filename = mFilename.getText().toString(); + + Intent intent = new Intent(FileManager.ACTION_PICK_FILE); + + intent.setData(Uri.parse("file://" + filename)); + + intent.putExtra(FileManager.EXTRA_TITLE, R.string.filemanager_titleEncrypt); + intent.putExtra(FileManager.EXTRA_BUTTON_TEXT, R.string.filemanager_btnOpen); + + try { + startActivityForResult(intent, Id.request.filename); + } catch (ActivityNotFoundException e) { + // No compatible file manager was found. + Toast.makeText(this, R.string.oiFilemanagerNotInstalled, Toast.LENGTH_SHORT).show(); + } + } + + private void guessOutputFilename() { + mInputFilename = mFilename.getText().toString(); + File file = new File(mInputFilename); + String ending = (mAsciiArmour.isChecked() ? ".asc" : ".gpg"); + mOutputFilename = Constants.path.app_dir + "/" + file.getName() + ending; + } + + private void updateSource() { + switch (mSource.getCurrentView().getId()) { + case R.id.sourceFile: { + mSourceLabel.setText(R.string.label_file); + mEncryptButton.setText(R.string.btn_encrypt); + mEncryptToClipboardButton.setEnabled(false); + break; + } + + case R.id.sourceMessage: { + mSourceLabel.setText(R.string.label_message); + mEncryptButton.setText(R.string.btn_send); + mEncryptToClipboardButton.setEnabled(true); + break; + } + + default: { + break; + } + } + } + + private void updateMode() { + switch (mMode.getCurrentView().getId()) { + case R.id.modeAsymmetric: { + mModeLabel.setText(R.string.label_asymmetric); + break; + } + + case R.id.modeSymmetric: { + mModeLabel.setText(R.string.label_symmetric); + break; + } + + default: { + break; + } + } + } + + private void encryptToClipboardClicked() { + mEncryptTarget = Id.target.clipboard; + initiateEncryption(); + } + + private void encryptClicked() { + if (mSource.getCurrentView().getId() == R.id.sourceFile) { + mEncryptTarget = Id.target.file; + } else { + mEncryptTarget = Id.target.email; + } + initiateEncryption(); + } + + private void initiateEncryption() { + if (mEncryptTarget == Id.target.file) { + String currentFilename = mFilename.getText().toString(); + if (mInputFilename == null || !mInputFilename.equals(currentFilename)) { + guessOutputFilename(); + } + + if (mInputFilename.equals("")) { + Toast.makeText(this, R.string.noFileSelected, Toast.LENGTH_SHORT).show(); + return; + } + + File file = new File(mInputFilename); + if (!file.exists() || !file.isFile()) { + Toast.makeText(this, getString(R.string.errorMessage, + getString(R.string.error_fileNotFound)), + Toast.LENGTH_SHORT).show(); + return; + } + } + + // symmetric encryption + if (mMode.getCurrentView().getId() == R.id.modeSymmetric) { + boolean gotPassPhrase = false; + String passPhrase = mPassPhrase.getText().toString(); + String passPhraseAgain = mPassPhraseAgain.getText().toString(); + if (!passPhrase.equals(passPhraseAgain)) { + Toast.makeText(this, R.string.passPhrasesDoNotMatch, Toast.LENGTH_SHORT).show(); + return; + } + + gotPassPhrase = (passPhrase.length() != 0); + if (!gotPassPhrase) { + Toast.makeText(this, R.string.passPhraseMustNotBeEmpty, Toast.LENGTH_SHORT).show(); + return; + } + } else { + boolean encryptIt = mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0; + // for now require at least one form of encryption for files + if (!encryptIt && mEncryptTarget == Id.target.file) { + Toast.makeText(this, R.string.selectEncryptionKey, Toast.LENGTH_SHORT).show(); + return; + } + + if (!encryptIt && getSecretKeyId() == 0) { + Toast.makeText(this, R.string.selectEncryptionOrSignatureKey, + Toast.LENGTH_SHORT).show(); + return; + } + + if (getSecretKeyId() != 0 && Apg.getCachedPassPhrase(getSecretKeyId()) == null) { + showDialog(Id.dialog.pass_phrase); + return; + } + } + + if (mEncryptTarget == Id.target.file) { + askForOutputFilename(); + } else { + encryptStart(); + } + } + + private void askForOutputFilename() { + showDialog(Id.dialog.output_filename); + } + + @Override + public void passPhraseCallback(long keyId, String passPhrase) { + super.passPhraseCallback(keyId, passPhrase); + if (mEncryptTarget == Id.target.file) { + askForOutputFilename(); + } else { + encryptStart(); + } + } + + private void encryptStart() { + showDialog(Id.dialog.encrypting); + startThread(); + } + + @Override + public void run() { + String error = null; + Bundle data = new Bundle(); + Message msg = new Message(); + + try { + InputStream in; + OutputStream out; + long size; + boolean useAsciiArmour = true; + long encryptionKeyIds[] = null; + long signatureKeyId = 0; + boolean signOnly = false; + int compressionId = 0; + + String passPhrase = null; + if (mMode.getCurrentView().getId() == R.id.modeSymmetric) { + passPhrase = mPassPhrase.getText().toString(); + if (passPhrase.length() == 0) { + passPhrase = null; + } + } else { + encryptionKeyIds = mEncryptionKeyIds; + signatureKeyId = getSecretKeyId(); + signOnly = mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0; + } + + if (mEncryptTarget == Id.target.file) { + if (mInputFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath()) || + mOutputFilename.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) { + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + throw new GeneralException(getString(R.string.error_externalStorageNotReady)); + } + } + + in = new FileInputStream(mInputFilename); + out = new FileOutputStream(mOutputFilename); + + File file = new File(mInputFilename); + size = file.length(); + useAsciiArmour = mAsciiArmour.isChecked(); + compressionId = ((Choice) mFileCompression.getSelectedItem()).getId(); + } else { + String message = mMessage.getText().toString(); + + if (signOnly) { + // fix the message a bit, trailing spaces and newlines break stuff, + // because GMail sends as HTML and such things fuck up the signature, + // TODO: things like "<" and ">" also fuck up the signature + message = message.replaceAll(" +\n", "\n"); + message = message.replaceAll("\n\n+", "\n\n"); + message = message.replaceFirst("^\n+", ""); + // make sure there'll be exactly one newline at the end + message = message.replaceFirst("\n*$", "\n"); + } + + byte[] byteData = Strings.toUTF8ByteArray(message); + in = new ByteArrayInputStream(byteData); + out = new ByteArrayOutputStream(); + + size = byteData.length; + useAsciiArmour = true; + compressionId = getDefaultMessageCompression(); + } + + if (signOnly) { + Apg.signText(this, in, out, getSecretKeyId(), + Apg.getCachedPassPhrase(getSecretKeyId()), + getDefaultHashAlgorithm(), this); + } else { + Apg.encrypt(this, in, out, size, useAsciiArmour, + encryptionKeyIds, signatureKeyId, + Apg.getCachedPassPhrase(signatureKeyId), this, + getDefaultEncryptionAlgorithm(), getDefaultHashAlgorithm(), + compressionId, passPhrase); + } + + out.close(); + if (mEncryptTarget != Id.target.file) { + data.putString("message", new String(((ByteArrayOutputStream)out).toByteArray())); + } + } catch (IOException e) { + error = e.getMessage(); + } catch (PGPException e) { + error = e.getMessage(); + } catch (NoSuchProviderException e) { + error = e.getMessage(); + } catch (NoSuchAlgorithmException e) { + error = e.getMessage(); + } catch (SignatureException e) { + error = e.getMessage(); + } catch (Apg.GeneralException e) { + error = e.getMessage(); + } + + data.putInt("type", Id.message.done); + + if (error != null) { + data.putString("error", error); + } + + msg.setData(data); + sendMessage(msg); + } + + private void updateView() { + if (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0) { + mSelectKeysButton.setText(R.string.noKeysSelected); + } else if (mEncryptionKeyIds.length == 1) { + mSelectKeysButton.setText(R.string.oneKeySelected); + } else { + mSelectKeysButton.setText("" + mEncryptionKeyIds.length + " " + + getResources().getString(R.string.nKeysSelected)); + } + + if (getSecretKeyId() == 0) { + mSign.setChecked(false); + mMainUserId.setText(""); + mMainUserIdRest.setText(""); + } else { + String uid = getResources().getString(R.string.unknownUserId); + String uidExtra = ""; + PGPSecretKeyRing keyRing = Apg.getSecretKeyRing(getSecretKeyId()); + if (keyRing != null) { + PGPSecretKey key = Apg.getMasterKey(keyRing); + if (key != null) { + String userId = Apg.getMainUserIdSafe(this, key); + String chunks[] = userId.split(" <", 2); + uid = chunks[0]; + if (chunks.length > 1) { + uidExtra = "<" + chunks[1]; + } + } + } + mMainUserId.setText(uid); + mMainUserIdRest.setText(uidExtra); + mSign.setChecked(true); + } + } + + private void selectPublicKeys() { + Intent intent = new Intent(this, SelectPublicKeyListActivity.class); + intent.putExtra("selection", mEncryptionKeyIds); + startActivityForResult(intent, Id.request.public_keys); + } + + private void selectSecretKey() { + Intent intent = new Intent(this, SelectSecretKeyListActivity.class); + startActivityForResult(intent, Id.request.secret_keys); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case Id.request.filename: { + if (resultCode == RESULT_OK && data != null) { + String filename = data.getDataString(); + if (filename != null) { + // Get rid of URI prefix: + if (filename.startsWith("file://")) { + filename = filename.substring(7); + } + // replace %20 and so on + filename = Uri.decode(filename); + + mFilename.setText(filename); + } + } + return; + } + + case Id.request.output_filename: { + if (resultCode == RESULT_OK && data != null) { + String filename = data.getDataString(); + if (filename != null) { + // Get rid of URI prefix: + if (filename.startsWith("file://")) { + filename = filename.substring(7); + } + // replace %20 and so on + filename = Uri.decode(filename); + + FileDialog.setFilename(filename); + } + } + return; + } + + case Id.request.secret_keys: { + if (resultCode == RESULT_OK) { + super.onActivityResult(requestCode, resultCode, data); + } + updateView(); + break; + } + + case Id.request.public_keys: { + if (resultCode == RESULT_OK) { + Bundle bundle = data.getExtras(); + mEncryptionKeyIds = bundle.getLongArray("selection"); + } + updateView(); + break; + } + + default: { + break; + } + } + + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void doneCallback(Message msg) { + super.doneCallback(msg); + + removeDialog(Id.dialog.encrypting); + + Bundle data = msg.getData(); + String error = data.getString("error"); + if (error != null) { + Toast.makeText(EncryptActivity.this, + getString(R.string.errorMessage, data.getString("error")), + Toast.LENGTH_SHORT).show(); + return; + } else { + String message = data.getString("message"); + switch (mEncryptTarget) { + case Id.target.clipboard: { + ClipboardManager clip = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + clip.setText(message); + Toast.makeText(this, R.string.encryptionToClipboardSuccessful, + Toast.LENGTH_SHORT).show(); + break; + } + + case Id.target.email: { + Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); + emailIntent.setType("text/plain; charset=utf-8"); + emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, message); + if (mSubject != null) { + emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, + mSubject); + } + if (mSendTo != null) { + emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, + new String[] { mSendTo }); + } + EncryptActivity.this. + startActivity(Intent.createChooser(emailIntent, + getString(R.string.title_sendEmail))); + } + + case Id.target.file: { + Toast.makeText(this, R.string.encryptionSuccessful, Toast.LENGTH_SHORT).show(); + if (mDeleteAfter.isChecked()) { + setDeleteFile(mInputFilename); + showDialog(Id.dialog.delete_file); + } + break; + } + + default: { + // shouldn't happen + break; + } + } + } + } + + @Override + protected Dialog onCreateDialog(int id) { + switch (id) { + case Id.dialog.output_filename: { + return FileDialog.build(this, getString(R.string.title_encryptToFile), + getString(R.string.specifyFileToEncryptTo), + mOutputFilename, + new FileDialog.OnClickListener() { + + @Override + public void onOkClick(String filename) { + removeDialog(Id.dialog.output_filename); + mOutputFilename = filename; + encryptStart(); + } + + @Override + public void onCancelClick() { + removeDialog(Id.dialog.output_filename); + } + }, + getString(R.string.filemanager_titleSave), + getString(R.string.filemanager_btnSave), + Id.request.output_filename); + } + + default: { + break; + } + } + + return super.onCreateDialog(id); + } +}
\ No newline at end of file diff --git a/src/org/thialfihar/android/apg/EncryptMessageActivity.java b/src/org/thialfihar/android/apg/EncryptMessageActivity.java deleted file mode 100644 index 27e4c29be..000000000 --- a/src/org/thialfihar/android/apg/EncryptMessageActivity.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.thialfihar.android.apg; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SignatureException; -import java.util.Vector; - -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPPublicKey; -import org.bouncycastle2.openpgp.PGPPublicKeyRing; -import org.bouncycastle2.openpgp.PGPSecretKey; -import org.bouncycastle2.openpgp.PGPSecretKeyRing; -import org.bouncycastle2.util.Strings; - -import android.app.Activity; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.TextView; -import android.widget.Toast; - -public class EncryptMessageActivity extends Activity - implements Runnable, ProgressDialogUpdater, - AskForSecretKeyPassPhrase.PassPhraseCallbackInterface { - static final int GET_PUCLIC_KEYS = 1; - static final int GET_SECRET_KEY = 2; - - static final int DIALOG_ENCRYPTING = 1; - - static final int MESSAGE_PROGRESS_UPDATE = 1; - static final int MESSAGE_DONE = 2; - - private String mSubject = null; - private String mSendTo = null; - - private long mEncryptionKeyIds[] = null; - private long mSignatureKeyId = 0; - - private ProgressDialog mProgressDialog = null; - private Thread mRunningThread = null; - - private EditText mMessage = null; - private Button mSelectKeysButton = null; - private Button mSendButton = null; - private CheckBox mSign = null; - private TextView mMainUserId = null; - private TextView mMainUserIdRest = null; - - private Handler mhandler = new Handler() { - @Override - public void handleMessage(Message mSg) { - Bundle data = mSg.getData(); - if (data != null) { - int type = data.getInt("type"); - switch (type) { - case MESSAGE_PROGRESS_UPDATE: { - String message = data.getString("message"); - if (mProgressDialog != null) { - if (message != null) { - mProgressDialog.setMessage(message); - } - mProgressDialog.setMax(data.getInt("max")); - mProgressDialog.setProgress(data.getInt("progress")); - } - break; - } - - case MESSAGE_DONE: { - removeDialog(DIALOG_ENCRYPTING); - mProgressDialog = null; - - String error = data.getString("error"); - if (error != null) { - Toast.makeText(EncryptMessageActivity.this, - "Error: " + data.getString("error"), - Toast.LENGTH_SHORT).show(); - return; - } else { - String message = data.getString("message"); - String signature = data.getString("signature"); - Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); - emailIntent.setType("text/plain; charset=utf-8"); - emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, message); - if (signature != null) { - String fullText = "-----BEGIN PGP SIGNED MESSAGE-----\n" + - "Hash: SHA256\n" + "\n" + - message + "\n" + signature; - emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, fullText); - } - if (mSubject != null) { - emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, - mSubject); - } - if (mSendTo != null) { - emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, - new String[] { mSendTo }); - } - EncryptMessageActivity.this. - startActivity(Intent.createChooser(emailIntent, "Send mail...")); - } - break; - } - - default: { - break; - } - } - } - } - }; - - @Override - public void setProgress(int progress, int max) { - Message msg = new Message(); - Bundle data = new Bundle(); - data.putInt("type", MESSAGE_PROGRESS_UPDATE); - data.putInt("progress", progress); - data.putInt("max", max); - msg.setData(data); - mhandler.sendMessage(msg); - } - - @Override - public void setProgress(String message, int progress, int max) { - Message msg = new Message(); - Bundle data = new Bundle(); - data.putInt("type", MESSAGE_PROGRESS_UPDATE); - data.putString("message", message); - data.putInt("progress", progress); - data.putInt("max", max); - msg.setData(data); - mhandler.sendMessage(msg); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.encrypt_message); - - Apg.initialize(this); - - mMessage = (EditText) findViewById(R.id.message); - mSelectKeysButton = (Button) findViewById(R.id.btn_selectEncryptKeys); - mSendButton = (Button) findViewById(R.id.btn_send); - mSign = (CheckBox) findViewById(R.id.sign); - mMainUserId = (TextView) findViewById(R.id.main_user_id); - mMainUserIdRest = (TextView) findViewById(R.id.main_user_id_rest); - - Intent intent = getIntent(); - if (intent.getAction() != null && - intent.getAction().equals(Apg.Intent.ENCRYPT)) { - String data = intent.getExtras().getString("data"); - mSendTo = intent.getExtras().getString("sendTo"); - mSubject = intent.getExtras().getString("subject"); - long signatureKeyId = intent.getExtras().getLong("signatureKeyId"); - long encryptionKeyIds[] = intent.getExtras().getLongArray("encryptionKeyIds"); - if (signatureKeyId != 0) { - PGPSecretKeyRing keyRing = Apg.findSecretKeyRing(signatureKeyId); - PGPSecretKey masterKey = null; - if (keyRing != null) { - masterKey = Apg.getMasterKey(keyRing); - if (masterKey != null) { - Vector<PGPSecretKey> signKeys = Apg.getUsableSigningKeys(keyRing); - if (signKeys.size() > 0) { - mSignatureKeyId = masterKey.getKeyID(); - } - } - } - } - - if (encryptionKeyIds != null) { - Vector<Long> goodIds = new Vector<Long>(); - for (int i = 0; i < encryptionKeyIds.length; ++i) { - PGPPublicKeyRing keyRing = Apg.findPublicKeyRing(encryptionKeyIds[i]); - PGPPublicKey masterKey = null; - if (keyRing == null) { - continue; - } - masterKey = Apg.getMasterKey(keyRing); - if (masterKey == null) { - continue; - } - Vector<PGPPublicKey> encryptKeys = Apg.getUsableEncryptKeys(keyRing); - if (encryptKeys.size() == 0) { - continue; - } - goodIds.add(masterKey.getKeyID()); - } - if (goodIds.size() > 0) { - mEncryptionKeyIds = new long[goodIds.size()]; - for (int i = 0; i < goodIds.size(); ++i) { - mEncryptionKeyIds[i] = goodIds.get(i); - } - } - } - if (data != null) { - mMessage.setText(data); - } - } - - mSendButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - sendClicked(); - } - }); - - mSelectKeysButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - selectPublicKeys(); - } - }); - - mSign.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - CheckBox checkBox = (CheckBox) v; - if (checkBox.isChecked()) { - selectSecretKey(); - } else { - mSignatureKeyId = 0; - Apg.setPassPhrase(null); - updateView(); - } - } - }); - - updateView(); - } - - @Override - protected Dialog onCreateDialog(int id) { - switch (id) { - case DIALOG_ENCRYPTING: { - mProgressDialog = new ProgressDialog(this); - mProgressDialog.setMessage("initializing..."); - mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - mProgressDialog.setCancelable(false); - return mProgressDialog; - } - - case AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE: { - return AskForSecretKeyPassPhrase.createDialog(this, mSignatureKeyId, this); - } - } - - return super.onCreateDialog(id); - } - - private void sendClicked() { - if (mSignatureKeyId != 0 && Apg.getPassPhrase() == null) { - showDialog(AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE); - } else { - encryptStart(); - } - } - - public void passPhraseCallback(String passPhrase) { - Apg.setPassPhrase(passPhrase); - encryptStart(); - } - - private void encryptStart() { - showDialog(DIALOG_ENCRYPTING); - mRunningThread = new Thread(this); - mRunningThread.start(); - } - - public void run() { - String error = null; - Bundle data = new Bundle(); - Message msg = new Message(); - String message = mMessage.getText().toString(); - // fix the message a bit, trailing spaces and newlines break stuff, - // because GMail sends as HTML and such things fuck up the signature, - // TODO: things like "<" and ">" also fuck up the signature - message = message.replaceAll(" +\n", "\n"); - message = message.replaceAll("\n\n+", "\n\n"); - message = message.replaceFirst("^\n+", ""); - message = message.replaceFirst("\n+$", ""); - ByteArrayInputStream in = - new ByteArrayInputStream(Strings.toUTF8ByteArray(message)); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - try { - if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) { - Apg.encrypt(in, out, mEncryptionKeyIds, mSignatureKeyId, Apg.getPassPhrase(), this); - data.putString("message", new String(out.toByteArray())); - } else { - Apg.sign(in, out, mSignatureKeyId, Apg.getPassPhrase(), this); - data.putString("message", message); - data.putString("signature", new String(out.toByteArray())); - } - } catch (IOException e) { - error = e.getMessage(); - } catch (PGPException e) { - error = e.getMessage(); - } catch (NoSuchProviderException e) { - error = e.getMessage(); - } catch (NoSuchAlgorithmException e) { - error = e.getMessage(); - } catch (SignatureException e) { - error = e.getMessage(); - } catch (Apg.GeneralException e) { - error = e.getMessage(); - } - - data.putInt("type", MESSAGE_DONE); - - if (error != null) { - data.putString("error", error); - } - - msg.setData(data); - mhandler.sendMessage(msg); - } - - private void updateView() { - if (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0) { - mSelectKeysButton.setText(R.string.no_keys_selected); - } else if (mEncryptionKeyIds.length == 1) { - mSelectKeysButton.setText(R.string.one_key_selected); - } else { - mSelectKeysButton.setText("" + mEncryptionKeyIds.length + " " + - getResources().getString(R.string.n_keys_selected)); - } - - if (mSignatureKeyId == 0) { - mSign.setText(R.string.sign); - mSign.setChecked(false); - mMainUserId.setText(""); - mMainUserIdRest.setText(""); - } else { - String uid = getResources().getString(R.string.unknown_user_id); - String uidExtra = ""; - PGPSecretKeyRing keyRing = Apg.getSecretKeyRing(mSignatureKeyId); - if (keyRing != null) { - PGPSecretKey key = Apg.getMasterKey(keyRing); - if (key != null) { - String userId = Apg.getMainUserIdSafe(this, key); - String chunks[] = userId.split(" <", 2); - uid = chunks[0]; - if (chunks.length > 1) { - uidExtra = "<" + chunks[1]; - } - } - } - mMainUserId.setText(uid); - mMainUserIdRest.setText(uidExtra); - mSign.setText(R.string.sign_as); - mSign.setChecked(true); - } - } - - private void selectPublicKeys() { - Intent intent = new Intent(this, SelectPublicKeyListActivity.class); - intent.putExtra("selection", mEncryptionKeyIds); - startActivityForResult(intent, GET_PUCLIC_KEYS); - } - - private void selectSecretKey() { - Intent intent = new Intent(this, SelectSecretKeyListActivity.class); - startActivityForResult(intent, GET_SECRET_KEY); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case GET_PUCLIC_KEYS: { - if (resultCode == RESULT_OK) { - Bundle bundle = data.getExtras(); - mEncryptionKeyIds = bundle.getLongArray("selection"); - updateView(); - } - break; - } - - case GET_SECRET_KEY: { - if (resultCode == RESULT_OK) { - Bundle bundle = data.getExtras(); - long newId = bundle.getLong("selectedKeyId"); - if (mSignatureKeyId != newId) { - Apg.setPassPhrase(null); - } - mSignatureKeyId = newId; - } else { - mSignatureKeyId = 0; - Apg.setPassPhrase(null); - } - updateView(); - break; - } - - default: - break; - } - - super.onActivityResult(requestCode, resultCode, data); - } -}
\ No newline at end of file diff --git a/src/org/thialfihar/android/apg/FileDialog.java b/src/org/thialfihar/android/apg/FileDialog.java new file mode 100644 index 000000000..22d64fc84 --- /dev/null +++ b/src/org/thialfihar/android/apg/FileDialog.java @@ -0,0 +1,119 @@ +/*
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thialfihar.android.apg;
+
+import org.openintents.intents.FileManager;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.Toast;
+
+public class FileDialog {
+ private static EditText mFilename;
+ private static ImageButton mBrowse;
+ private static Activity mActivity;
+ private static String mFileManagerTitle;
+ private static String mFileManagerButton;
+ private static int mRequestCode;
+
+ public static interface OnClickListener {
+ public void onCancelClick();
+ public void onOkClick(String filename);
+ }
+
+ public static AlertDialog build(Activity activity, String title, String message,
+ String defaultFile, OnClickListener onClickListener,
+ String fileManagerTitle, String fileManagerButton,
+ int requestCode) {
+ LayoutInflater inflater =
+ (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ AlertDialog.Builder alert = new AlertDialog.Builder(activity);
+
+ alert.setTitle(title);
+ alert.setMessage(message);
+
+ View view = (View) inflater.inflate(R.layout.file_dialog, null);
+
+ mActivity = activity;
+ mFilename = (EditText) view.findViewById(R.id.input);
+ mFilename.setText(defaultFile);
+ mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
+ mBrowse.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openFile();
+ }
+ });
+ mFileManagerTitle = fileManagerTitle;
+ mFileManagerButton = fileManagerButton;
+ mRequestCode = requestCode;
+
+ alert.setView(view);
+
+ final OnClickListener clickListener = onClickListener;
+
+ alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ clickListener.onOkClick(mFilename.getText().toString());
+ }
+ });
+
+ alert.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ clickListener.onCancelClick();
+ }
+ });
+ return alert.create();
+ }
+
+ public static void setFilename(String filename) {
+ if (mFilename != null) {
+ mFilename.setText(filename);
+ }
+ }
+
+ /**
+ * Opens the file manager to select a file to open.
+ */
+ private static void openFile() {
+ String filename = mFilename.getText().toString();
+
+ Intent intent = new Intent(FileManager.ACTION_PICK_FILE);
+
+ intent.setData(Uri.parse("file://" + filename));
+
+ intent.putExtra(FileManager.EXTRA_TITLE, mFileManagerTitle);
+ intent.putExtra(FileManager.EXTRA_BUTTON_TEXT, mFileManagerButton);
+
+ try {
+ mActivity.startActivityForResult(intent, mRequestCode);
+ } catch (ActivityNotFoundException e) {
+ // No compatible file manager was found.
+ Toast.makeText(mActivity, R.string.oiFilemanagerNotInstalled, Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/src/org/thialfihar/android/apg/Id.java b/src/org/thialfihar/android/apg/Id.java new file mode 100644 index 000000000..47cd0a890 --- /dev/null +++ b/src/org/thialfihar/android/apg/Id.java @@ -0,0 +1,129 @@ +/*
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thialfihar.android.apg;
+
+import org.bouncycastle2.bcpg.CompressionAlgorithmTags;
+
+public final class Id {
+ public static final class menu {
+ public static final int export = 0x21070001;
+ public static final int delete = 0x21070002;
+ public static final int edit = 0x21070003;
+
+ public static final class option {
+ public static final int new_pass_phrase = 0x21070001;
+ public static final int create = 0x21070002;
+ public static final int about = 0x21070003;
+ public static final int manage_public_keys = 0x21070004;
+ public static final int manage_secret_keys = 0x21070005;
+ public static final int import_keys = 0x21070006;
+ public static final int export_keys = 0x21070007;
+ public static final int preferences = 0x21070008;
+ }
+ }
+
+ public static final class message {
+ public static final int progress_update = 0x21070001;
+ public static final int done = 0x21070002;
+ public static final int import_keys = 0x21070003;
+ public static final int export_keys = 0x21070004;
+ public static final int import_done = 0x21070005;
+ public static final int export_done = 0x21070006;
+ public static final int create_key = 0x21070007;
+ public static final int edit_key = 0x21070008;
+ }
+
+ public static final class request {
+ public static final int public_keys = 0x21070001;
+ public static final int secret_keys = 0x21070002;
+ public static final int filename = 0x21070003;
+ public static final int output_filename = 0x21070004;
+ }
+
+ public static final class dialog {
+ public static final int pass_phrase = 0x21070001;
+ public static final int encrypting = 0x21070002;
+ public static final int decrypting = 0x21070003;
+ public static final int new_pass_phrase = 0x21070004;
+ public static final int pass_phrases_do_not_match = 0x21070005;
+ public static final int no_pass_phrase = 0x21070006;
+ public static final int saving = 0x21070007;
+ public static final int delete_key = 0x21070008;
+ public static final int import_keys = 0x21070009;
+ public static final int importing = 0x2107000a;
+ public static final int export_key = 0x2107000b;
+ public static final int export_keys = 0x2107000c;
+ public static final int exporting = 0x2107000d;
+ public static final int new_account = 0x2107000e;
+ public static final int about = 0x2107000f;
+ public static final int change_log = 0x21070010;
+ public static final int output_filename = 0x21070011;
+ public static final int delete_file = 0x21070012;
+ }
+
+ public static final class task {
+ public static final int import_keys = 0x21070001;
+ public static final int export_keys = 0x21070002;
+ }
+
+ public static final class type {
+ public static final int public_key = 0x21070001;
+ public static final int secret_key = 0x21070002;
+ public static final int user_id = 0x21070003;
+ public static final int key = 0x21070004;
+ }
+
+ public static final class choice {
+ public static final class algorithm {
+ public static final int dsa = 0x21070001;
+ public static final int elgamal = 0x21070002;
+ public static final int rsa = 0x21070003;
+ }
+
+ public static final class compression {
+ public static final int none = 0x21070001;
+ public static final int zlib = CompressionAlgorithmTags.ZLIB;
+ public static final int bzip2 = CompressionAlgorithmTags.BZIP2;
+ public static final int zip = CompressionAlgorithmTags.ZIP;
+ }
+
+ public static final class usage {
+ public static final int sign_only = 0x21070001;
+ public static final int encrypt_only = 0x21070002;
+ public static final int sign_and_encrypt = 0x21070003;
+ }
+ }
+
+ public static final class return_value {
+ public static final int ok = 0;
+ public static final int error = -1;
+ public static final int no_master_key = -2;
+ public static final int updated = 1;
+ }
+
+ public static final class target {
+ public static final int clipboard = 0x21070001;
+ public static final int email = 0x21070002;
+ public static final int file = 0x21070003;
+ public static final int message = 0x21070004;
+ }
+
+ public static final class key {
+ public static final int none = 0;
+ public static final int symmetric = -1;
+ }
+}
diff --git a/src/org/thialfihar/android/apg/MailListActivity.java b/src/org/thialfihar/android/apg/MailListActivity.java index 8e63a7920..f0abe8f45 100644 --- a/src/org/thialfihar/android/apg/MailListActivity.java +++ b/src/org/thialfihar/android/apg/MailListActivity.java @@ -37,9 +37,9 @@ import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener;
public class MailListActivity extends ListActivity {
- LayoutInflater minflater = null;
+ LayoutInflater mInflater = null;
- private class Conversation {
+ private static class Conversation {
public long id;
public String subject;
public Vector<Message> messages;
@@ -50,16 +50,18 @@ public class MailListActivity extends ListActivity { }
}
- private class Message {
+ private static class Message {
public Conversation parent;
public long id;
public String subject;
public String fromAddress;
public String data;
public String replyTo;
+ public boolean signedOnly;
public Message(Conversation parent, long id, String subject,
- String fromAddress, String replyTo, String data) {
+ String fromAddress, String replyTo,
+ String data, boolean signedOnly) {
this.parent = parent;
this.id = id;
this.subject = subject;
@@ -69,6 +71,7 @@ public class MailListActivity extends ListActivity { if (this.replyTo == null || this.replyTo.equals("")) {
this.replyTo = this.fromAddress;
}
+ this.signedOnly = signedOnly;
}
}
@@ -79,7 +82,7 @@ public class MailListActivity extends ListActivity { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- minflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mconversations = new Vector<Conversation>();
mmessages = new Vector<Message>();
@@ -115,18 +118,26 @@ public class MailListActivity extends ListActivity { int bodyIndex = messageCursor.getColumnIndex("body");
String data = messageCursor.getString(bodyIndex);
data = Html.fromHtml(data).toString();
+ boolean signedOnly = false;
Matcher matcher = Apg.PGP_MESSAGE.matcher(data);
if (matcher.matches()) {
data = matcher.group(1);
} else {
- data = null;
+ matcher = Apg.PGP_SIGNED_MESSAGE.matcher(data);
+ if (matcher.matches()) {
+ data = matcher.group(1);
+ signedOnly = true;
+ } else {
+ data = null;
+ }
}
Message message =
new Message(conversation,
messageCursor.getLong(idIndex),
messageCursor.getString(subjectIndex),
messageCursor.getString(fromAddressIndex),
- messageCursor.getString(replyToIndex), data);
+ messageCursor.getString(replyToIndex),
+ data, signedOnly);
messages.add(message);
mmessages.add(message);
@@ -139,7 +150,7 @@ public class MailListActivity extends ListActivity { getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
- Intent intent = new Intent(MailListActivity.this, DecryptMessageActivity.class);
+ Intent intent = new Intent(MailListActivity.this, DecryptActivity.class);
intent.setAction(Apg.Intent.DECRYPT);
Message message = (Message) ((MailboxAdapter) getListAdapter()).getItem(position);
intent.putExtra("data", message.data);
@@ -180,20 +191,25 @@ public class MailListActivity extends ListActivity { @Override
public View getView(int position, View convertView, ViewGroup parent) {
- View view = minflater.inflate(R.layout.mailbox_message_item, null);
+ View view = mInflater.inflate(R.layout.mailbox_message_item, null);
Message message = (Message) getItem(position);
TextView subject = (TextView) view.findViewById(R.id.subject);
- TextView email = (TextView) view.findViewById(R.id.email_address);
- ImageView encrypted = (ImageView) view.findViewById(R.id.ic_encrypted);
+ TextView email = (TextView) view.findViewById(R.id.emailAddress);
+ ImageView status = (ImageView) view.findViewById(R.id.ic_status);
subject.setText(message.subject);
email.setText(message.fromAddress);
if (message.data != null) {
- encrypted.setVisibility(View.VISIBLE);
+ if (message.signedOnly) {
+ status.setImageResource(R.drawable.signed);
+ } else {
+ status.setImageResource(R.drawable.encrypted);
+ }
+ status.setVisibility(View.VISIBLE);
} else {
- encrypted.setVisibility(View.INVISIBLE);
+ status.setVisibility(View.INVISIBLE);
}
return view;
diff --git a/src/org/thialfihar/android/apg/MainActivity.java b/src/org/thialfihar/android/apg/MainActivity.java index e7107f255..a4d584304 100644 --- a/src/org/thialfihar/android/apg/MainActivity.java +++ b/src/org/thialfihar/android/apg/MainActivity.java @@ -18,21 +18,16 @@ package org.thialfihar.android.apg; import org.thialfihar.android.apg.provider.Accounts; -import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.SharedPreferences; import android.database.Cursor; import android.database.SQLException; import android.net.Uri; import android.os.Bundle; -import android.text.SpannableString; -import android.text.method.LinkMovementMethod; -import android.text.util.Linkify; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; @@ -46,25 +41,11 @@ import android.widget.Button; import android.widget.CursorAdapter; import android.widget.EditText; import android.widget.ListView; -import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; -public class MainActivity extends Activity { - private static final int DIALOG_NEW_ACCOUNT = 1; - private static final int DIALOG_ABOUT = 2; - private static final int DIALOG_CHANGE_LOG = 3; - - private static final int OPTION_MENU_ADD_ACCOUNT = 1; - private static final int OPTION_MENU_ABOUT = 2; - private static final int OPTION_MENU_MANAGE_PUBLIC_KEYS = 3; - private static final int OPTION_MENU_MANAGE_SECRET_KEYS = 4; - - private static final int MENU_DELETE_ACCOUNT = 1; - - private static String PREF_SEEN_CHANGE_LOG = "seenChangeLogDialog" + Apg.VERSION; - +public class MainActivity extends BaseActivity { private ListView mAccounts = null; @Override @@ -74,19 +55,43 @@ public class MainActivity extends Activity { Button encryptMessageButton = (Button) findViewById(R.id.btn_encryptMessage); Button decryptMessageButton = (Button) findViewById(R.id.btn_decryptMessage); - mAccounts = (ListView) findViewById(R.id.account_list); + Button encryptFileButton = (Button) findViewById(R.id.btn_encryptFile); + Button decryptFileButton = (Button) findViewById(R.id.btn_decryptFile); + mAccounts = (ListView) findViewById(R.id.accounts); encryptMessageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - startEncryptMessageActivity(); + Intent intent = new Intent(MainActivity.this, EncryptActivity.class); + intent.setAction(Apg.Intent.ENCRYPT); + startActivity(intent); } }); decryptMessageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - startDecryptMessageActivity(); + Intent intent = new Intent(MainActivity.this, DecryptActivity.class); + intent.setAction(Apg.Intent.DECRYPT); + startActivity(intent); + } + }); + + encryptFileButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, EncryptActivity.class); + intent.setAction(Apg.Intent.ENCRYPT_FILE); + startActivity(intent); + } + }); + + decryptFileButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, DecryptActivity.class); + intent.setAction(Apg.Intent.DECRYPT_FILE); + startActivity(intent); } }); @@ -103,157 +108,106 @@ public class MainActivity extends Activity { cursor.moveToFirst(); int nameIndex = cursor.getColumnIndex(Accounts.NAME); String accountName = cursor.getString(nameIndex); - startMailListActivity(accountName); + startActivity(new Intent(MainActivity.this, MailListActivity.class) + .putExtra("account", accountName)); } } }); registerForContextMenu(mAccounts); - SharedPreferences prefs = getPreferences(MODE_PRIVATE); - if (!prefs.getBoolean(PREF_SEEN_CHANGE_LOG, false)) { - showDialog(DIALOG_CHANGE_LOG); + if (!hasSeenChangeLog()) { + showDialog(Id.dialog.change_log); } } @Override protected Dialog onCreateDialog(int id) { switch (id) { - case DIALOG_NEW_ACCOUNT: { + case Id.dialog.new_account: { AlertDialog.Builder alert = new AlertDialog.Builder(this); - alert.setTitle("Add Account"); - alert.setMessage("Specify the Google Mail account you want to add."); + alert.setTitle(R.string.title_addAccount); + alert.setMessage(R.string.specifyGoogleMailAccount); final EditText input = new EditText(this); alert.setView(input); alert.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - MainActivity.this.removeDialog(DIALOG_NEW_ACCOUNT); - String accountName = "" + input.getText(); - - Cursor testCursor = - managedQuery(Uri.parse("content://gmail-ls/conversations/" + - accountName), - null, null, null, null); - if (testCursor == null) { - Toast.makeText(MainActivity.this, - "Error: account '" + accountName + - "' not found", - Toast.LENGTH_SHORT).show(); - return; - } - - ContentValues values = new ContentValues(); - values.put(Accounts.NAME, accountName); - try { - MainActivity.this.getContentResolver() - .insert(Accounts.CONTENT_URI, - values); - } catch (SQLException e) { - Toast.makeText(MainActivity.this, - "Error: failed to add account '" + - accountName + "'", - Toast.LENGTH_SHORT).show(); - } - } - }); + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + MainActivity.this.removeDialog(Id.dialog.new_account); + String accountName = "" + input.getText(); + + Cursor testCursor = + managedQuery(Uri.parse("content://gmail-ls/conversations/" + + accountName), + null, null, null, null); + if (testCursor == null) { + Toast.makeText(MainActivity.this, + getString(R.string.errorMessage, + getString(R.string.error_accountNotFound, + accountName)), + Toast.LENGTH_SHORT).show(); + return; + } + + ContentValues values = new ContentValues(); + values.put(Accounts.NAME, accountName); + try { + MainActivity.this.getContentResolver() + .insert(Accounts.CONTENT_URI, + values); + } catch (SQLException e) { + Toast.makeText(MainActivity.this, + getString(R.string.errorMessage, + getString(R.string.error_addingAccountFailed, + accountName)), + Toast.LENGTH_SHORT).show(); + } + } + }); alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - MainActivity.this.removeDialog(DIALOG_NEW_ACCOUNT); + MainActivity.this.removeDialog(Id.dialog.new_account); } }); return alert.create(); } - case DIALOG_ABOUT: { - AlertDialog.Builder alert = new AlertDialog.Builder(this); - - alert.setTitle("About " + Apg.FULL_VERSION); - ScrollView scrollView = new ScrollView(this); - TextView message = new TextView(this); - - SpannableString info = - new SpannableString("This is an attempt to bring OpenPGP to Android. " + - "It is far from complete, but more features are " + - "planned (see website).\n" + - "\n" + - "Feel free to send bug reports, suggestions, feature " + - "requests, feedback, photographs.\n" + - "\n" + - "mail: thi@thialfihar.org\n" + - "site: http://apg.thialfihar.org\n" + - "\n" + - "This software is provided \"as is\", without " + - "warranty of any kind."); - Linkify.addLinks(info, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES); - message.setMovementMethod(LinkMovementMethod.getInstance()); - message.setText(info); - // 5dip padding - int padding = (int) (10 * getResources().getDisplayMetrics().densityDpi / 160); - message.setPadding(padding, padding, padding, padding); - message.setTextAppearance(this, android.R.style.TextAppearance_Medium); - scrollView.addView(message); - alert.setView(scrollView); - - alert.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - MainActivity.this.removeDialog(DIALOG_ABOUT); - } - }); - - return alert.create(); - } - - case DIALOG_CHANGE_LOG: { + case Id.dialog.change_log: { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("Changes " + Apg.FULL_VERSION); - ScrollView scrollView = new ScrollView(this); - TextView message = new TextView(this); - - SpannableString info = - new SpannableString("Read the warnings!\n\n" + - "Changes:\n" + - " * create/edit keys\n" + - " * export keys\n" + - " * GUI more Android-like\n" + - " * better error handling\n" + - " * bug fixes, optimizations\n" + - " * starting with v0.8.0 APG will be open source, see website\n" + - "\n" + - "WARNING: be careful editing your existing keys, as they " + - "WILL be stripped of certificates right now.\n" + - "WARNING: key creation/editing doesn't support all " + - "GPG features yet. In particular: " + - "key cross-certification is NOT supported, so signing " + - "with those keys will get a warning when the signature is " + - "checked.\n" + - "\n" + - "I hope APG continues to be useful to you, please send " + - "bug reports, feature wishes, feedback."); - message.setText(info); - // 5dip padding - int padding = (int) (10 * getResources().getDisplayMetrics().densityDpi / 160); - message.setPadding(padding, padding, padding, padding); - message.setTextAppearance(this, android.R.style.TextAppearance_Medium); - scrollView.addView(message); - alert.setView(scrollView); + LayoutInflater inflater = + (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View layout = inflater.inflate(R.layout.info, null); + TextView message = (TextView) layout.findViewById(R.id.message); + + message.setText("Read the warnings!\n\n" + + "Changes:\n" + + "\n" + + "WARNING: be careful editing your existing keys, as they " + + "WILL be stripped of certificates right now.\n" + + "\n" + + "WARNING: key creation/editing doesn't support all " + + "GPG features yet. In particular: " + + "key cross-certification is NOT supported, so signing " + + "with those keys will get a warning when the signature is " + + "checked.\n" + + "\n" + + "I hope APG continues to be useful to you, please send " + + "bug reports, feature wishes, feedback."); + alert.setView(layout); alert.setCancelable(false); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - MainActivity.this.removeDialog(DIALOG_CHANGE_LOG); - SharedPreferences prefs = getPreferences(MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(PREF_SEEN_CHANGE_LOG, true); - editor.commit(); + MainActivity.this.removeDialog(Id.dialog.change_log); + setHasSeenChangeLog(true); } }); @@ -261,21 +215,22 @@ public class MainActivity extends Activity { } default: { - break; + return super.onCreateDialog(id); } } - return super.onCreateDialog(id); } @Override public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, OPTION_MENU_MANAGE_PUBLIC_KEYS, 0, R.string.menu_managePublicKeys) + menu.add(0, Id.menu.option.create, 0, R.string.menu_addAccount) + .setIcon(android.R.drawable.ic_menu_add); + menu.add(1, Id.menu.option.manage_public_keys, 1, R.string.menu_managePublicKeys) .setIcon(android.R.drawable.ic_menu_manage); - menu.add(0, OPTION_MENU_MANAGE_SECRET_KEYS, 1, R.string.menu_manageSecretKeys) + menu.add(1, Id.menu.option.manage_secret_keys, 2, R.string.menu_manageSecretKeys) .setIcon(android.R.drawable.ic_menu_manage); - menu.add(1, OPTION_MENU_ADD_ACCOUNT, 2, R.string.menu_addAccount) - .setIcon(android.R.drawable.ic_menu_add); - menu.add(1, OPTION_MENU_ABOUT, 3, R.string.menu_about) + menu.add(2, Id.menu.option.preferences, 3, R.string.menu_preferences) + .setIcon(android.R.drawable.ic_menu_preferences); + menu.add(2, Id.menu.option.about, 4, R.string.menu_about) .setIcon(android.R.drawable.ic_menu_info_details); return true; } @@ -283,41 +238,35 @@ public class MainActivity extends Activity { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case OPTION_MENU_ADD_ACCOUNT: { - showDialog(DIALOG_NEW_ACCOUNT); - return true; - } - - case OPTION_MENU_ABOUT: { - showDialog(DIALOG_ABOUT); + case Id.menu.option.create: { + showDialog(Id.dialog.new_account); return true; } - case OPTION_MENU_MANAGE_PUBLIC_KEYS: { - startPublicKeyManager(); + case Id.menu.option.manage_public_keys: { + startActivity(new Intent(this, PublicKeyListActivity.class)); return true; } - case OPTION_MENU_MANAGE_SECRET_KEYS: { - startSecretKeyManager(); + case Id.menu.option.manage_secret_keys: { + startActivity(new Intent(this, SecretKeyListActivity.class)); return true; } default: { - break; + return super.onOptionsItemSelected(item); } } - return false; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); - TextView nameTextView = (TextView) v.findViewById(R.id.account_name); + TextView nameTextView = (TextView) v.findViewById(R.id.accountName); if (nameTextView != null) { menu.setHeaderTitle(nameTextView.getText()); - menu.add(0, MENU_DELETE_ACCOUNT, 0, "Delete Account"); + menu.add(0, Id.menu.delete, 0, R.string.menu_deleteAccount); } } @@ -327,7 +276,7 @@ public class MainActivity extends Activity { (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); switch (menuItem.getItemId()) { - case MENU_DELETE_ACCOUNT: { + case Id.menu.delete: { Uri uri = Uri.withAppendedPath(Accounts.CONTENT_URI, "" + info.id); this.getContentResolver().delete(uri, null, null); return true; @@ -339,28 +288,8 @@ public class MainActivity extends Activity { } } - public void startPublicKeyManager() { - startActivity(new Intent(this, PublicKeyListActivity.class)); - } - - public void startSecretKeyManager() { - startActivity(new Intent(this, SecretKeyListActivity.class)); - //startActivity(new Intent(this, EditKeyActivity.class)); - } - - public void startEncryptMessageActivity() { - startActivity(new Intent(this, EncryptMessageActivity.class)); - } - - public void startDecryptMessageActivity() { - startActivity(new Intent(this, DecryptMessageActivity.class)); - } - - public void startMailListActivity(String account) { - startActivity(new Intent(this, MailListActivity.class).putExtra("account", account)); - } - private class AccountListAdapter extends CursorAdapter { + private static class AccountListAdapter extends CursorAdapter { private LayoutInflater minflater; public AccountListAdapter(Context context, Cursor cursor) { @@ -380,7 +309,7 @@ public class MainActivity extends Activity { @Override public void bindView(View view, Context context, Cursor cursor) { - TextView nameTextView = (TextView) view.findViewById(R.id.account_name); + TextView nameTextView = (TextView) view.findViewById(R.id.accountName); int nameIndex = cursor.getColumnIndex(Accounts.NAME); final String account = cursor.getString(nameIndex); nameTextView.setText(account); diff --git a/src/org/thialfihar/android/apg/PositionAwareInputStream.java b/src/org/thialfihar/android/apg/PositionAwareInputStream.java new file mode 100644 index 000000000..661e053f2 --- /dev/null +++ b/src/org/thialfihar/android/apg/PositionAwareInputStream.java @@ -0,0 +1,67 @@ +package org.thialfihar.android.apg;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class PositionAwareInputStream extends InputStream {
+ private InputStream mStream;
+ private long mPosition;
+
+ public PositionAwareInputStream(InputStream in) {
+ mStream = in;
+ mPosition = 0;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int ch = mStream.read();
+ ++mPosition;
+ return ch;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return mStream.available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ mStream.close();
+ }
+
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ int result = mStream.read(b);
+ mPosition += result;
+ return result;
+ }
+
+ @Override
+ public int read(byte[] b, int offset, int length) throws IOException {
+ int result = mStream.read(b, offset, length);
+ mPosition += result;
+ return result;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ mStream.reset();
+ mPosition = 0;
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ long result = mStream.skip(n);
+ mPosition += result;
+ return result;
+ }
+
+ public long position() {
+ return mPosition;
+ }
+}
diff --git a/src/org/thialfihar/android/apg/PreferencesActivity.java b/src/org/thialfihar/android/apg/PreferencesActivity.java new file mode 100644 index 000000000..fae63d63b --- /dev/null +++ b/src/org/thialfihar/android/apg/PreferencesActivity.java @@ -0,0 +1,222 @@ +/*
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thialfihar.android.apg;
+
+import org.bouncycastle2.bcpg.HashAlgorithmTags;
+import org.bouncycastle2.openpgp.PGPEncryptedData;
+import org.thialfihar.android.apg.utils.Choice;
+
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+public class PreferencesActivity extends BaseActivity {
+ private Spinner mPassPhraseCacheTtl = null;
+ private Spinner mEncryptionAlgorithm = null;
+ private Spinner mHashAlgorithm = null;
+ private Spinner mMessageCompression = null;
+ private Spinner mFileCompression = null;
+ private CheckBox mAsciiArmour = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.preferences);
+
+ mPassPhraseCacheTtl = (Spinner) findViewById(R.id.passPhraseCacheTtl);
+
+ Choice choices[] = {
+ new Choice(15, getString(R.string.choice_15secs)),
+ new Choice(60, getString(R.string.choice_1min)),
+ new Choice(180, getString(R.string.choice_3mins)),
+ new Choice(300, getString(R.string.choice_5mins)),
+ new Choice(600, getString(R.string.choice_10mins)),
+ new Choice(0, getString(R.string.choice_untilQuit)),
+ };
+ ArrayAdapter<Choice> adapter =
+ new ArrayAdapter<Choice>(this, android.R.layout.simple_spinner_item, choices);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mPassPhraseCacheTtl.setAdapter(adapter);
+
+ int passPhraseCache = getPassPhraseCacheTtl();
+ for (int i = 0; i < choices.length; ++i) {
+ if (choices[i].getId() == passPhraseCache) {
+ mPassPhraseCacheTtl.setSelection(i);
+ break;
+ }
+ }
+
+ mPassPhraseCacheTtl.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> adapter, View view, int index, long id) {
+ setPassPhraseCacheTtl(((Choice) mPassPhraseCacheTtl.getSelectedItem()).getId());
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> adapter) {
+ // nothing to do
+ }
+ });
+
+ mEncryptionAlgorithm = (Spinner) findViewById(R.id.encryptionAlgorithm);
+ choices = new Choice[] {
+ new Choice(PGPEncryptedData.AES_128, "AES 128"),
+ new Choice(PGPEncryptedData.AES_192, "AES 192"),
+ new Choice(PGPEncryptedData.AES_256, "AES 256"),
+ new Choice(PGPEncryptedData.BLOWFISH, "Blowfish"),
+ new Choice(PGPEncryptedData.TWOFISH, "Twofish"),
+ new Choice(PGPEncryptedData.CAST5, "CAST5"),
+ new Choice(PGPEncryptedData.DES, "DES"),
+ new Choice(PGPEncryptedData.TRIPLE_DES, "Triple DES"),
+ new Choice(PGPEncryptedData.IDEA, "IDEA"),
+ };
+ adapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_spinner_item, choices);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mEncryptionAlgorithm.setAdapter(adapter);
+
+ int defaultEncryptionAlgorithm = getDefaultEncryptionAlgorithm();
+ for (int i = 0; i < choices.length; ++i) {
+ if (choices[i].getId() == defaultEncryptionAlgorithm) {
+ mEncryptionAlgorithm.setSelection(i);
+ break;
+ }
+ }
+
+ mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> adapter, View view, int index, long id) {
+ setDefaultEncryptionAlgorithm(((Choice) mEncryptionAlgorithm.getSelectedItem()).getId());
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> adapter) {
+ // nothing to do
+ }
+ });
+
+ mHashAlgorithm = (Spinner) findViewById(R.id.hashAlgorithm);
+ choices = new Choice[] {
+ new Choice(HashAlgorithmTags.MD5, "MD5"),
+ new Choice(HashAlgorithmTags.RIPEMD160, "RIPEMD160"),
+ new Choice(HashAlgorithmTags.SHA1, "SHA1"),
+ new Choice(HashAlgorithmTags.SHA224, "SHA224"),
+ new Choice(HashAlgorithmTags.SHA256, "SHA256"),
+ new Choice(HashAlgorithmTags.SHA384, "SHA384"),
+ new Choice(HashAlgorithmTags.SHA512, "SHA512"),
+ };
+ adapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_spinner_item, choices);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mHashAlgorithm.setAdapter(adapter);
+
+ int defaultHashAlgorithm = getDefaultHashAlgorithm();
+ for (int i = 0; i < choices.length; ++i) {
+ if (choices[i].getId() == defaultHashAlgorithm) {
+ mHashAlgorithm.setSelection(i);
+ break;
+ }
+ }
+
+ mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> adapter, View view, int index, long id) {
+ setDefaultHashAlgorithm(((Choice) mHashAlgorithm.getSelectedItem()).getId());
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> adapter) {
+ // nothing to do
+ }
+ });
+
+ mMessageCompression = (Spinner) findViewById(R.id.messageCompression);
+ choices = new Choice[] {
+ new Choice(Id.choice.compression.none, getString(R.string.choice_none)),
+ new Choice(Id.choice.compression.zip, "ZIP"),
+ new Choice(Id.choice.compression.bzip2, "BZIP2"),
+ new Choice(Id.choice.compression.zlib, "ZLIB"),
+ };
+ adapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_spinner_item, choices);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mMessageCompression.setAdapter(adapter);
+
+ int defaultMessageCompression = getDefaultMessageCompression();
+ for (int i = 0; i < choices.length; ++i) {
+ if (choices[i].getId() == defaultMessageCompression) {
+ mMessageCompression.setSelection(i);
+ break;
+ }
+ }
+
+ mMessageCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> adapter, View view, int index, long id) {
+ setDefaultMessageCompression(((Choice) mMessageCompression.getSelectedItem()).getId());
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> adapter) {
+ // nothing to do
+ }
+ });
+
+ mFileCompression = (Spinner) findViewById(R.id.fileCompression);
+ choices = new Choice[] {
+ new Choice(Id.choice.compression.none, getString(R.string.choice_none)),
+ new Choice(Id.choice.compression.zip, "ZIP"),
+ new Choice(Id.choice.compression.bzip2, "BZIP2"),
+ new Choice(Id.choice.compression.zlib, "ZLIB"),
+ };
+ adapter = new ArrayAdapter<Choice>(this, android.R.layout.simple_spinner_item, choices);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mFileCompression.setAdapter(adapter);
+
+ int defaultFileCompression = getDefaultFileCompression();
+ for (int i = 0; i < choices.length; ++i) {
+ if (choices[i].getId() == defaultFileCompression) {
+ mFileCompression.setSelection(i);
+ break;
+ }
+ }
+
+ mFileCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> adapter, View view, int index, long id) {
+ setDefaultFileCompression(((Choice) mFileCompression.getSelectedItem()).getId());
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> adapter) {
+ // nothing to do
+ }
+ });
+
+ mAsciiArmour = (CheckBox) findViewById(R.id.asciiArmour);
+ mAsciiArmour.setChecked(getDefaultAsciiArmour());
+ mAsciiArmour.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setDefaultAsciiArmour(mAsciiArmour.isChecked());
+ }
+ });
+ }
+}
+
diff --git a/src/org/thialfihar/android/apg/Primes.java b/src/org/thialfihar/android/apg/Primes.java new file mode 100644 index 000000000..e97a6c6c5 --- /dev/null +++ b/src/org/thialfihar/android/apg/Primes.java @@ -0,0 +1,185 @@ +/*
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thialfihar.android.apg;
+
+import java.math.BigInteger;
+
+public final class Primes {
+ // taken from http://www.ietf.org/rfc/rfc3526.txt
+ public static final String P1536 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
+
+ public static final String P2048 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
+
+ public static final String P3072 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
+
+ public static final String P4096 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
+ "FFFFFFFF FFFFFFFF";
+
+ public static final String P6144 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
+ "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
+
+ public static final String P8192 =
+ "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
+ "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
+ "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
+ "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
+ "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
+ "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
+ "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
+ "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
+ "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
+ "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
+ "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
+ "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
+ "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
+ "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
+ "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
+ "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
+ "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
+ "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
+ "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
+ "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
+ "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
+ "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
+ "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
+ "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
+ "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
+ "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
+ "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
+ "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
+ "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
+ "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
+ "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
+ "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
+ "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
+ "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
+ "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
+ "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
+ "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
+ "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
+ "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
+ "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
+ "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
+ "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
+ "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
+
+ public static BigInteger getBestPrime(int keySize) {
+ String primeString;
+ if (keySize >= (8192 + 6144) / 2) {
+ primeString = P8192;
+ } else if (keySize >= (6144 + 4096) / 2) {
+ primeString = P6144;
+ } else if (keySize >= (4096 + 3072) / 2) {
+ primeString = P4096;
+ } else if (keySize >= (3072 + 2048) / 2) {
+ primeString = P3072;
+ } else if (keySize >= (2048 + 1536) / 2) {
+ primeString = P2048;
+ } else {
+ primeString = P1536;
+ }
+
+ return new BigInteger(primeString.replaceAll(" ", ""), 16);
+ }
+}
diff --git a/src/org/thialfihar/android/apg/ProgressDialogUpdater.java b/src/org/thialfihar/android/apg/ProgressDialogUpdater.java index bdc8055ed..fe38c2a34 100644 --- a/src/org/thialfihar/android/apg/ProgressDialogUpdater.java +++ b/src/org/thialfihar/android/apg/ProgressDialogUpdater.java @@ -18,5 +18,6 @@ package org.thialfihar.android.apg; public interface ProgressDialogUpdater {
void setProgress(String message, int current, int total);
+ void setProgress(int resourceId, int current, int total);
void setProgress(int current, int total);
}
diff --git a/src/org/thialfihar/android/apg/PublicKeyListActivity.java b/src/org/thialfihar/android/apg/PublicKeyListActivity.java index cebd9c7ae..67bc608ad 100644 --- a/src/org/thialfihar/android/apg/PublicKeyListActivity.java +++ b/src/org/thialfihar/android/apg/PublicKeyListActivity.java @@ -27,201 +27,75 @@ import org.thialfihar.android.apg.utils.IterableIterator; import android.app.AlertDialog;
import android.app.Dialog;
-import android.app.ExpandableListActivity;
-import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
import android.os.Message;
import android.view.ContextMenu;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.OnKeyListener;
import android.widget.BaseExpandableListAdapter;
-import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
-public class PublicKeyListActivity extends ExpandableListActivity
- implements Runnable, ProgressDialogUpdater {
- static final int MENU_DELETE = 1;
- static final int MENU_EXPORT = 2;
-
- static final int OPTION_MENU_IMPORT_KEYS = 1;
- static final int OPTION_MENU_EXPORT_KEYS = 2;
-
- static final int MESSAGE_PROGRESS_UPDATE = 1;
- static final int MESSAGE_IMPORT_DONE = 2;
- static final int MESSAGE_EXPORT_DONE = 3;
-
- static final int DIALOG_DELETE_KEY = 1;
- static final int DIALOG_IMPORT_KEYS = 2;
- static final int DIALOG_IMPORTING = 3;
- static final int DIALOG_EXPORT_KEYS = 4;
- static final int DIALOG_EXPORTING = 5;
- static final int DIALOG_EXPORT_KEY = 6;
-
- static final int TASK_IMPORT = 1;
- static final int TASK_EXPORT = 2;
+public class PublicKeyListActivity extends BaseActivity {
+ ExpandableListView mList;
protected int mSelectedItem = -1;
- protected String mImportFilename = null;
- protected String mExportFilename = null;
protected int mTask = 0;
- private ProgressDialog mProgressDialog = null;
- private Thread mRunningThread = null;
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- Bundle data = msg.getData();
- if (data != null) {
- int type = data.getInt("type");
- switch (type) {
- case MESSAGE_PROGRESS_UPDATE: {
- String message = data.getString("message");
- if (mProgressDialog != null) {
- if (message != null) {
- mProgressDialog.setMessage(message);
- }
- mProgressDialog.setMax(data.getInt("max"));
- mProgressDialog.setProgress(data.getInt("progress"));
- }
- break;
- }
-
- case MESSAGE_IMPORT_DONE: {
- removeDialog(DIALOG_IMPORTING);
- mProgressDialog = null;
-
- String error = data.getString("error");
- if (error != null) {
- Toast.makeText(PublicKeyListActivity.this,
- "Error: " + data.getString("error"),
- Toast.LENGTH_SHORT).show();
- } else {
- int added = data.getInt("added");
- int updated = data.getInt("updated");
- String message;
- if (added > 0 && updated > 0) {
- message = "Succssfully added " + added + " keys and updated " +
- updated + " keys.";
- } else if (added > 0) {
- message = "Succssfully added " + added + " keys.";
- } else if (updated > 0) {
- message = "Succssfully updated " + updated + " keys.";
- } else {
- message = "No keys added or updated.";
- }
- Toast.makeText(PublicKeyListActivity.this, message,
- Toast.LENGTH_SHORT).show();
- }
- refreshList();
- break;
- }
-
- case MESSAGE_EXPORT_DONE: {
- removeDialog(DIALOG_EXPORTING);
- mProgressDialog = null;
-
- String error = data.getString("error");
- if (error != null) {
- Toast.makeText(PublicKeyListActivity.this,
- "Error: " + data.getString("error"),
- Toast.LENGTH_SHORT).show();
- } else {
- int exported = data.getInt("exported");
- String message;
- if (exported == 1) {
- message = "Succssfully exported 1 key.";
- } else if (exported > 0) {
- message = "Succssfully exported " + exported + " keys.";
- } else{
- message = "No keys exported.";
- }
- Toast.makeText(PublicKeyListActivity.this, message,
- Toast.LENGTH_SHORT).show();
- }
- break;
- }
-
- default: {
- break;
- }
- }
- }
- }
- };
-
- public void setProgress(int progress, int max) {
- Message msg = new Message();
- Bundle data = new Bundle();
- data.putInt("type", MESSAGE_PROGRESS_UPDATE);
- data.putInt("progress", progress);
- data.putInt("max", max);
- msg.setData(data);
- mHandler.sendMessage(msg);
- }
-
- public void setProgress(String message, int progress, int max) {
- Message msg = new Message();
- Bundle data = new Bundle();
- data.putInt("type", MESSAGE_PROGRESS_UPDATE);
- data.putString("message", message);
- data.putInt("progress", progress);
- data.putInt("max", max);
- msg.setData(data);
- mHandler.sendMessage(msg);
- }
+ private String mImportFilename = Constants.path.app_dir + "/pubring.gpg";
+ private String mExportFilename = Constants.path.app_dir + "/pubexport.asc";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.key_list);
- Apg.initialize(this);
-
- setListAdapter(new PublicKeyListAdapter(this));
- registerForContextMenu(getExpandableListView());
+ mList = (ExpandableListView) findViewById(R.id.list);
+ mList.setAdapter(new PublicKeyListAdapter(this));
+ registerForContextMenu(mList);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, OPTION_MENU_IMPORT_KEYS, 0, "Import Keys")
+ menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
.setIcon(android.R.drawable.ic_menu_add);
- menu.add(0, OPTION_MENU_EXPORT_KEYS, 1, "Export Keys")
+ menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
.setIcon(android.R.drawable.ic_menu_save);
+ menu.add(1, Id.menu.option.preferences, 2, R.string.menu_preferences)
+ .setIcon(android.R.drawable.ic_menu_preferences);
+ menu.add(1, Id.menu.option.about, 3, R.string.menu_about)
+ .setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case OPTION_MENU_IMPORT_KEYS: {
- showDialog(DIALOG_IMPORT_KEYS);
+ case Id.menu.option.import_keys: {
+ showDialog(Id.dialog.import_keys);
return true;
}
- case OPTION_MENU_EXPORT_KEYS: {
- showDialog(DIALOG_EXPORT_KEYS);
+ case Id.menu.option.export_keys: {
+ showDialog(Id.dialog.export_keys);
return true;
}
default: {
- break;
+ return super.onOptionsItemSelected(item);
}
}
- return false;
}
@Override
@@ -236,8 +110,8 @@ public class PublicKeyListActivity extends ExpandableListActivity PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(groupPosition);
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
menu.setHeaderTitle(userId);
- menu.add(0, MENU_EXPORT, 0, "Export Key");
- menu.add(0, MENU_DELETE, 1, "Delete Key");
+ menu.add(0, Id.menu.export, 0, R.string.menu_exportKey);
+ menu.add(0, Id.menu.delete, 1, R.string.menu_deleteKey);
}
}
@@ -252,15 +126,15 @@ public class PublicKeyListActivity extends ExpandableListActivity }
switch (menuItem.getItemId()) {
- case MENU_EXPORT: {
+ case Id.menu.export: {
mSelectedItem = groupPosition;
- showDialog(DIALOG_EXPORT_KEY);
+ showDialog(Id.dialog.export_key);
return true;
}
- case MENU_DELETE: {
+ case Id.menu.delete: {
mSelectedItem = groupPosition;
- showDialog(DIALOG_DELETE_KEY);
+ showDialog(Id.dialog.delete_key);
return true;
}
@@ -275,167 +149,123 @@ public class PublicKeyListActivity extends ExpandableListActivity boolean singleKeyExport = false;
switch (id) {
- case DIALOG_DELETE_KEY: {
+ case Id.dialog.delete_key: {
PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(mSelectedItem);
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle("Warning ");
- builder.setMessage("Do you really want to delete the key '" + userId + "'?\n" +
- "You can't undo this!");
+ builder.setTitle(R.string.warning);
+ builder.setMessage(getString(R.string.keyDeletionConfirmation, userId));
builder.setIcon(android.R.drawable.ic_dialog_alert);
- builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
+ builder.setPositiveButton(R.string.btn_delete,
+ new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
deleteKey(mSelectedItem);
mSelectedItem = -1;
- removeDialog(DIALOG_DELETE_KEY);
+ removeDialog(Id.dialog.delete_key);
}
});
builder.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mSelectedItem = -1;
- removeDialog(DIALOG_DELETE_KEY);
+ removeDialog(Id.dialog.delete_key);
}
});
return builder.create();
}
- case DIALOG_IMPORT_KEYS: {
- AlertDialog.Builder alert = new AlertDialog.Builder(this);
-
- alert.setTitle("Import Keys");
- alert.setMessage("Please specify which file to import from.");
-
- final EditText input = new EditText(this);
- // TODO: default file?
- input.setText(Environment.getExternalStorageDirectory() + "/pubring.gpg");
- input.setOnKeyListener(new OnKeyListener() {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // TODO: this doesn't actually work yet
- // If the event is a key-down event on the "enter"
- // button
- if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
- (keyCode == KeyEvent.KEYCODE_ENTER)) {
- try {
- ((AlertDialog) v.getParent())
- .getButton(AlertDialog.BUTTON_POSITIVE)
- .performClick();
- } catch (ClassCastException e) {
- // don't do anything if we're not in that dialog
- }
- return true;
- }
- return false;
- }
- });
- alert.setView(input);
+ case Id.dialog.import_keys: {
+ return FileDialog.build(this, getString(R.string.title_importKeys),
+ getString(R.string.specifyFileToImportFrom),
+ mImportFilename,
+ new FileDialog.OnClickListener() {
- alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- removeDialog(DIALOG_IMPORT_KEYS);
- mImportFilename = input.getText().toString();
+ @Override
+ public void onOkClick(String filename) {
+ removeDialog(Id.dialog.import_keys);
+ mImportFilename = filename;
importKeys();
}
- });
- alert.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- removeDialog(DIALOG_IMPORT_KEYS);
+ @Override
+ public void onCancelClick() {
+ removeDialog(Id.dialog.import_keys);
}
- });
- return alert.create();
+ },
+ getString(R.string.filemanager_titleOpen),
+ getString(R.string.filemanager_btnOpen),
+ Id.request.filename);
}
- case DIALOG_EXPORT_KEY: {
+ case Id.dialog.export_key: {
singleKeyExport = true;
- // break intentionally omitted, to use the DIALOG_EXPORT_KEYS dialog
+ // break intentionally omitted, to use the Id.dialog.export_keys dialog
}
- case DIALOG_EXPORT_KEYS: {
- AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ case Id.dialog.export_keys: {
+ String title = (singleKeyExport ?
+ getString(R.string.title_exportKey) :
+ getString(R.string.title_exportKeys));
- if (singleKeyExport) {
- alert.setTitle("Export Key");
- } else {
- alert.setTitle("Export Keys");
- mSelectedItem = -1;
- }
- final int thisDialogId = (singleKeyExport ? DIALOG_DELETE_KEY : DIALOG_EXPORT_KEYS);
- alert.setMessage("Please specify which file to export to.\n" +
- "WARNING! File will be overwritten if it exists.");
+ final int thisDialogId = (singleKeyExport ? Id.dialog.export_key : Id.dialog.export_keys);
- final EditText input = new EditText(this);
- // TODO: default file?
- input.setText(Environment.getExternalStorageDirectory() + "/pubexport.asc");
- alert.setView(input);
+ return FileDialog.build(this, title,
+ getString(R.string.specifyFileToExportTo),
+ mExportFilename,
+ new FileDialog.OnClickListener() {
- alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
+ @Override
+ public void onOkClick(String filename) {
removeDialog(thisDialogId);
- mExportFilename = input.getText().toString();
+ mExportFilename = filename;
exportKeys();
}
- });
- alert.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
+ @Override
+ public void onCancelClick() {
removeDialog(thisDialogId);
}
- });
- return alert.create();
+ },
+ getString(R.string.filemanager_titleSave),
+ getString(R.string.filemanager_btnSave),
+ Id.request.filename);
}
- case DIALOG_IMPORTING: {
- mProgressDialog = new ProgressDialog(this);
- mProgressDialog.setMessage("importing...");
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setCancelable(false);
- return mProgressDialog;
- }
-
- case DIALOG_EXPORTING: {
- mProgressDialog = new ProgressDialog(this);
- mProgressDialog.setMessage("exporting...");
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setCancelable(false);
- return mProgressDialog;
+ default: {
+ return super.onCreateDialog(id);
}
}
- return super.onCreateDialog(id);
}
public void importKeys() {
- showDialog(DIALOG_IMPORTING);
- mTask = TASK_IMPORT;
- mRunningThread = new Thread(this);
- mRunningThread.start();
+ showDialog(Id.dialog.importing);
+ mTask = Id.task.import_keys;
+ startThread();
}
public void exportKeys() {
- showDialog(DIALOG_EXPORTING);
- mTask = TASK_EXPORT;
- mRunningThread = new Thread(this);
- mRunningThread.start();
+ showDialog(Id.dialog.exporting);
+ mTask = Id.task.export_keys;
+ startThread();
}
+ @Override
public void run() {
String error = null;
Bundle data = new Bundle();
Message msg = new Message();
String filename = null;
- if (mTask == TASK_IMPORT) {
+ if (mTask == Id.task.import_keys) {
filename = mImportFilename;
} else {
filename = mExportFilename;
}
try {
- if (mTask == TASK_IMPORT) {
- data = Apg.importKeyRings(this, Apg.TYPE_PUBLIC, filename, this);
+ if (mTask == Id.task.import_keys) {
+ data = Apg.importKeyRings(this, Id.type.public_key, filename, this);
} else {
Vector<Object> keys = new Vector<Object>();
if (mSelectedItem == -1) {
@@ -448,7 +278,7 @@ public class PublicKeyListActivity extends ExpandableListActivity data = Apg.exportKeyRings(this, keys, filename, this);
}
} catch (FileNotFoundException e) {
- error = "file '" + filename + "' not found";
+ error = getString(R.string.error_fileNotFound);
} catch (IOException e) {
error = e.getMessage();
} catch (PGPException e) {
@@ -457,10 +287,10 @@ public class PublicKeyListActivity extends ExpandableListActivity error = e.getMessage();
}
- if (mTask == TASK_IMPORT) {
- data.putInt("type", MESSAGE_IMPORT_DONE);
+ if (mTask == Id.task.import_keys) {
+ data.putInt("type", Id.message.import_done);
} else {
- data.putInt("type", MESSAGE_EXPORT_DONE);
+ data.putInt("type", Id.message.export_done);
}
if (error != null) {
@@ -468,7 +298,7 @@ public class PublicKeyListActivity extends ExpandableListActivity }
msg.setData(data);
- mHandler.sendMessage(msg);
+ sendMessage(msg);
}
private void deleteKey(int index) {
@@ -478,10 +308,77 @@ public class PublicKeyListActivity extends ExpandableListActivity }
private void refreshList() {
- ((PublicKeyListAdapter) getExpandableListAdapter()).notifyDataSetChanged();
+ ((PublicKeyListAdapter) mList.getExpandableListAdapter()).notifyDataSetChanged();
}
- private class PublicKeyListAdapter extends BaseExpandableListAdapter {
+ @Override
+ public void doneCallback(Message msg) {
+ super.doneCallback(msg);
+
+ Bundle data = msg.getData();
+ if (data != null) {
+ int type = data.getInt("type");
+ switch (type) {
+ case Id.message.import_done: {
+ removeDialog(Id.dialog.importing);
+
+ String error = data.getString("error");
+ if (error != null) {
+ Toast.makeText(PublicKeyListActivity.this,
+ getString(R.string.errorMessage, data.getString("error")),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ int added = data.getInt("added");
+ int updated = data.getInt("updated");
+ String message;
+ if (added > 0 && updated > 0) {
+ message = getString(R.string.keysAddedAndUpdated, added, updated);
+ } else if (added > 0) {
+ message = getString(R.string.keysAdded, added);
+ } else if (updated > 0) {
+ message = getString(R.string.keysUpdated, updated);
+ } else {
+ message = getString(R.string.noKeysAddedOrUpdated);
+ }
+ Toast.makeText(PublicKeyListActivity.this, message,
+ Toast.LENGTH_SHORT).show();
+ }
+ refreshList();
+ break;
+ }
+
+ case Id.message.export_done: {
+ removeDialog(Id.dialog.exporting);
+
+ String error = data.getString("error");
+ if (error != null) {
+ Toast.makeText(PublicKeyListActivity.this,
+ getString(R.string.errorMessage, data.getString("error")),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ int exported = data.getInt("exported");
+ String message;
+ if (exported == 1) {
+ message = getString(R.string.keyExported);
+ } else if (exported > 0) {
+ message = getString(R.string.keysExported);
+ } else{
+ message = getString(R.string.noKeysExported);
+ }
+ Toast.makeText(PublicKeyListActivity.this, message,
+ Toast.LENGTH_SHORT).show();
+ }
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+ }
+ }
+
+ private static class PublicKeyListAdapter extends BaseExpandableListAdapter {
private LayoutInflater mInflater;
private class KeyChild {
@@ -581,9 +478,9 @@ public class PublicKeyListActivity extends ExpandableListActivity view = mInflater.inflate(R.layout.key_list_group_item, null);
view.setBackgroundResource(android.R.drawable.list_selector_background);
- TextView mainUserId = (TextView) view.findViewById(R.id.main_user_id);
+ TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText("");
- TextView mainUserIdRest = (TextView) view.findViewById(R.id.main_user_id_rest);
+ TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
String userId = Apg.getMainUserId(key);
@@ -597,7 +494,7 @@ public class PublicKeyListActivity extends ExpandableListActivity }
if (mainUserId.getText().length() == 0) {
- mainUserId.setText(R.string.unknown_user_id);
+ mainUserId.setText(R.string.unknownUserId);
}
if (mainUserIdRest.getText().length() == 0) {
@@ -625,22 +522,22 @@ public class PublicKeyListActivity extends ExpandableListActivity view = mInflater.inflate(R.layout.key_list_child_item_sub_key, null);
}
- TextView keyId = (TextView) view.findViewById(R.id.key_id);
+ TextView keyId = (TextView) view.findViewById(R.id.keyId);
String keyIdStr = Long.toHexString(key.getKeyID() & 0xffffffffL);
while (keyIdStr.length() < 8) {
keyIdStr = "0" + keyIdStr;
}
keyId.setText(keyIdStr);
- TextView keyDetails = (TextView) view.findViewById(R.id.key_details);
+ TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
String algorithmStr = Apg.getAlgorithmInfo(key);
keyDetails.setText("(" + algorithmStr + ")");
- ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encrypt_key);
+ ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
if (!Apg.isEncryptionKey(key)) {
encryptIcon.setVisibility(View.GONE);
}
- ImageView signIcon = (ImageView) view.findViewById(R.id.ic_sign_key);
+ ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
if (!Apg.isSigningKey(key)) {
signIcon.setVisibility(View.GONE);
}
@@ -649,7 +546,7 @@ public class PublicKeyListActivity extends ExpandableListActivity case KeyChild.USER_ID: {
view = mInflater.inflate(R.layout.key_list_child_item_user_id, null);
- TextView userId = (TextView) view.findViewById(R.id.user_id);
+ TextView userId = (TextView) view.findViewById(R.id.userId);
userId.setText(child.userId);
break;
}
@@ -657,4 +554,32 @@ public class PublicKeyListActivity extends ExpandableListActivity return view;
}
}
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case Id.request.filename: {
+ if (resultCode == RESULT_OK && data != null) {
+ String filename = data.getDataString();
+ if (filename != null) {
+ // Get rid of URI prefix:
+ if (filename.startsWith("file://")) {
+ filename = filename.substring(7);
+ }
+ // replace %20 and so on
+ filename = Uri.decode(filename);
+
+ FileDialog.setFilename(filename);
+ }
+
+ }
+ return;
+ }
+
+ default: {
+ break;
+ }
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
diff --git a/src/org/thialfihar/android/apg/SecretKeyListActivity.java b/src/org/thialfihar/android/apg/SecretKeyListActivity.java index f42b4ccad..a69fc5b9c 100644 --- a/src/org/thialfihar/android/apg/SecretKeyListActivity.java +++ b/src/org/thialfihar/android/apg/SecretKeyListActivity.java @@ -27,27 +27,20 @@ import org.thialfihar.android.apg.utils.IterableIterator; import android.app.AlertDialog;
import android.app.Dialog;
-import android.app.ExpandableListActivity;
-import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
import android.os.Message;
-import android.util.Log;
import android.view.ContextMenu;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.OnKeyListener;
import android.widget.BaseExpandableListAdapter;
-import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.TextView;
@@ -55,196 +48,67 @@ import android.widget.Toast; import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ExpandableListView.OnChildClickListener;
-public class SecretKeyListActivity extends ExpandableListActivity
- implements Runnable, ProgressDialogUpdater, OnChildClickListener,
- AskForSecretKeyPassPhrase.PassPhraseCallbackInterface {
- static final int CREATE_SECRET_KEY = 1;
- static final int EDIT_SECRET_KEY = 2;
-
- static final int MENU_EDIT = 1;
- static final int MENU_EXPORT = 2;
- static final int MENU_DELETE = 3;
-
- static final int OPTION_MENU_IMPORT_KEYS = 1;
- static final int OPTION_MENU_EXPORT_KEYS = 2;
- static final int OPTION_MENU_CREATE_KEY = 3;
-
- static final int MESSAGE_PROGRESS_UPDATE = 1;
- static final int MESSAGE_DONE = 2;
- static final int MESSAGE_IMPORT_DONE = 2;
- static final int MESSAGE_EXPORT_DONE = 3;
-
- static final int DIALOG_DELETE_KEY = 1;
- static final int DIALOG_IMPORT_KEYS = 2;
- static final int DIALOG_IMPORTING = 3;
- static final int DIALOG_EXPORT_KEYS = 4;
- static final int DIALOG_EXPORTING = 5;
- static final int DIALOG_EXPORT_KEY = 6;
-
- static final int TASK_IMPORT = 1;
- static final int TASK_EXPORT = 2;
+public class SecretKeyListActivity extends BaseActivity implements OnChildClickListener {
+ ExpandableListView mList;
protected int mSelectedItem = -1;
- protected String mImportFilename = null;
- protected String mExportFilename = null;
protected int mTask = 0;
- private ProgressDialog mProgressDialog = null;
- private Thread mRunningThread = null;
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- Bundle data = msg.getData();
- if (data != null) {
- int type = data.getInt("type");
- switch (type) {
- case MESSAGE_PROGRESS_UPDATE: {
- String message = data.getString("message");
- if (mProgressDialog != null) {
- if (message != null) {
- mProgressDialog.setMessage(message);
- }
- mProgressDialog.setMax(data.getInt("max"));
- mProgressDialog.setProgress(data.getInt("progress"));
- }
- break;
- }
-
- case MESSAGE_IMPORT_DONE: {
- removeDialog(DIALOG_IMPORTING);
- mProgressDialog = null;
-
- String error = data.getString("error");
- if (error != null) {
- Toast.makeText(SecretKeyListActivity.this,
- "Error: " + data.getString("error"),
- Toast.LENGTH_SHORT).show();
- } else {
- int added = data.getInt("added");
- int updated = data.getInt("updated");
- String message;
- if (added > 0 && updated > 0) {
- message = "Succssfully added " + added + " keys and updated " +
- updated + " keys.";
- } else if (added > 0) {
- message = "Succssfully added " + added + " keys.";
- } else if (updated > 0) {
- message = "Succssfully updated " + updated + " keys.";
- } else {
- message = "No keys added or updated.";
- }
- Toast.makeText(SecretKeyListActivity.this, message,
- Toast.LENGTH_SHORT).show();
- }
- refreshList();
- break;
- }
-
- case MESSAGE_EXPORT_DONE: {
- removeDialog(DIALOG_EXPORTING);
- mProgressDialog = null;
-
- String error = data.getString("error");
- if (error != null) {
- Toast.makeText(SecretKeyListActivity.this,
- "Error: " + data.getString("error"),
- Toast.LENGTH_SHORT).show();
- } else {
- int exported = data.getInt("exported");
- String message;
- if (exported == 1) {
- message = "Succssfully exported 1 key.";
- } else if (exported > 0) {
- message = "Succssfully exported " + exported + " keys.";
- } else{
- message = "No keys exported.";
- }
- Toast.makeText(SecretKeyListActivity.this, message,
- Toast.LENGTH_SHORT).show();
- }
- break;
- }
-
- default: {
- break;
- }
- }
- }
- }
- };
-
- public void setProgress(int progress, int max) {
- Message msg = new Message();
- Bundle data = new Bundle();
- data.putInt("type", MESSAGE_PROGRESS_UPDATE);
- data.putInt("progress", progress);
- data.putInt("max", max);
- msg.setData(data);
- mHandler.sendMessage(msg);
- }
-
- public void setProgress(String message, int progress, int max) {
- Message msg = new Message();
- Bundle data = new Bundle();
- data.putInt("type", MESSAGE_PROGRESS_UPDATE);
- data.putString("message", message);
- data.putInt("progress", progress);
- data.putInt("max", max);
- msg.setData(data);
- mHandler.sendMessage(msg);
- }
+ private String mImportFilename = Constants.path.app_dir + "/secring.gpg";
+ private String mExportFilename = Constants.path.app_dir + "/secexport.asc";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.key_list);
- Apg.initialize(this);
-
- setListAdapter(new SecretKeyListAdapter(this));
- registerForContextMenu(getExpandableListView());
- getExpandableListView().setOnChildClickListener(this);
+ mList = (ExpandableListView) findViewById(R.id.list);
+ mList.setAdapter(new SecretKeyListAdapter(this));
+ registerForContextMenu(mList);
+ mList.setOnChildClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, OPTION_MENU_IMPORT_KEYS, 0, "Import Keys")
+ menu.add(0, Id.menu.option.import_keys, 0, R.string.menu_importKeys)
.setIcon(android.R.drawable.ic_menu_add);
- menu.add(0, OPTION_MENU_EXPORT_KEYS, 1, "Export Keys")
+ menu.add(0, Id.menu.option.export_keys, 1, R.string.menu_exportKeys)
.setIcon(android.R.drawable.ic_menu_save);
- menu.add(1, OPTION_MENU_CREATE_KEY, 2, "Create Key")
+ menu.add(1, Id.menu.option.create, 2, R.string.menu_createKey)
.setIcon(android.R.drawable.ic_menu_add);
+ menu.add(2, Id.menu.option.preferences, 3, R.string.menu_preferences)
+ .setIcon(android.R.drawable.ic_menu_preferences);
+ menu.add(2, Id.menu.option.about, 4, R.string.menu_about)
+ .setIcon(android.R.drawable.ic_menu_info_details);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case OPTION_MENU_IMPORT_KEYS: {
- showDialog(DIALOG_IMPORT_KEYS);
+ case Id.menu.option.import_keys: {
+ showDialog(Id.dialog.import_keys);
return true;
}
- case OPTION_MENU_EXPORT_KEYS: {
- showDialog(DIALOG_EXPORT_KEYS);
+ case Id.menu.option.export_keys: {
+ showDialog(Id.dialog.export_keys);
return true;
}
- case OPTION_MENU_CREATE_KEY: {
+ case Id.menu.option.create: {
createKey();
return true;
}
default: {
- break;
+ return super.onOptionsItemSelected(item);
}
}
- return false;
}
@Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
ExpandableListView.ExpandableListContextMenuInfo info =
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
@@ -255,9 +119,9 @@ public class SecretKeyListActivity extends ExpandableListActivity PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(groupPosition);
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
menu.setHeaderTitle(userId);
- menu.add(0, MENU_EDIT, 0, "Edit Key");
- menu.add(0, MENU_EXPORT, 1, "Export Key");
- menu.add(0, MENU_DELETE, 2, "Delete Key");
+ menu.add(0, Id.menu.edit, 0, R.string.menu_editKey);
+ menu.add(0, Id.menu.export, 1, R.string.menu_exportKey);
+ menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey);
}
}
@@ -272,21 +136,21 @@ public class SecretKeyListActivity extends ExpandableListActivity }
switch (menuItem.getItemId()) {
- case MENU_EDIT: {
+ case Id.menu.edit: {
mSelectedItem = groupPosition;
- showDialog(AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE);
+ checkPassPhraseAndEdit();
return true;
}
- case MENU_EXPORT: {
+ case Id.menu.export: {
mSelectedItem = groupPosition;
- showDialog(DIALOG_EXPORT_KEY);
+ showDialog(Id.dialog.export_key);
return true;
}
- case MENU_DELETE: {
+ case Id.menu.delete: {
mSelectedItem = groupPosition;
- showDialog(DIALOG_DELETE_KEY);
+ showDialog(Id.dialog.delete_key);
return true;
}
@@ -300,7 +164,7 @@ public class SecretKeyListActivity extends ExpandableListActivity public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
mSelectedItem = groupPosition;
- showDialog(AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE);
+ checkPassPhraseAndEdit();
return true;
}
@@ -309,174 +173,125 @@ public class SecretKeyListActivity extends ExpandableListActivity boolean singleKeyExport = false;
switch (id) {
- case DIALOG_DELETE_KEY: {
+ case Id.dialog.delete_key: {
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(mSelectedItem);
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle("Warning ");
- builder.setMessage("Do you really want to delete the key '" + userId + "'?\n" +
- "You can't undo this!");
+ builder.setTitle(R.string.warning);
+ builder.setMessage(getString(R.string.secretKeyDeletionConfirmation, userId));
builder.setIcon(android.R.drawable.ic_dialog_alert);
- builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
+ builder.setPositiveButton(R.string.btn_delete,
+ new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
deleteKey(mSelectedItem);
mSelectedItem = -1;
- removeDialog(DIALOG_DELETE_KEY);
+ removeDialog(Id.dialog.delete_key);
}
});
builder.setNegativeButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mSelectedItem = -1;
- removeDialog(DIALOG_DELETE_KEY);
+ removeDialog(Id.dialog.delete_key);
}
});
return builder.create();
}
- case DIALOG_IMPORT_KEYS: {
- AlertDialog.Builder alert = new AlertDialog.Builder(this);
-
- alert.setTitle("Import Keys");
- alert.setMessage("Please specify which file to import from.");
-
- final EditText input = new EditText(this);
- // TODO: default file?
- input.setText(Environment.getExternalStorageDirectory() + "/secring.gpg");
- input.setOnKeyListener(new OnKeyListener() {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // TODO: this doesn't actually work yet
- // If the event is a key-down event on the "enter"
- // button
- if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
- (keyCode == KeyEvent.KEYCODE_ENTER)) {
- try {
- ((AlertDialog) v.getParent())
- .getButton(AlertDialog.BUTTON_POSITIVE)
- .performClick();
- } catch (ClassCastException e) {
- // don't do anything if we're not in that dialog
- }
- return true;
- }
- return false;
- }
- });
- alert.setView(input);
-
- alert.setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- removeDialog(DIALOG_IMPORT_KEYS);
- mImportFilename = input.getText().toString();
+ case Id.dialog.import_keys: {
+ return FileDialog.build(this, getString(R.string.title_importKeys),
+ getString(R.string.specifyFileToImportFrom),
+ mImportFilename,
+ new FileDialog.OnClickListener() {
+
+ @Override
+ public void onOkClick(String filename) {
+ removeDialog(Id.dialog.import_keys);
+ mImportFilename = filename;
importKeys();
}
- });
- alert.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- removeDialog(DIALOG_IMPORT_KEYS);
+ @Override
+ public void onCancelClick() {
+ removeDialog(Id.dialog.import_keys);
}
- });
- return alert.create();
+ },
+ getString(R.string.filemanager_titleOpen),
+ getString(R.string.filemanager_btnOpen),
+ Id.request.filename);
}
- case DIALOG_EXPORT_KEY: {
+ case Id.dialog.export_key: {
singleKeyExport = true;
- // break intentionally omitted, to use the DIALOG_EXPORT_KEYS dialog
+ // break intentionally omitted, to use the Id.dialog.export_keys dialog
}
- case DIALOG_EXPORT_KEYS: {
- AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ case Id.dialog.export_keys: {
+ String title = (singleKeyExport ?
+ getString(R.string.title_exportKey) :
+ getString(R.string.title_exportKeys));
- if (singleKeyExport) {
- alert.setTitle("Export Key");
- } else {
- alert.setTitle("Export Keys");
- mSelectedItem = -1;
- }
- final int thisDialogId = (singleKeyExport ? DIALOG_DELETE_KEY : DIALOG_EXPORT_KEYS);
- alert.setMessage("Please specify which file to export to.\n" +
- "WARNING! You are about to export a SECRET key.\n" +
- "WARNING! File will be overwritten if it exists.");
-
- final EditText input = new EditText(this);
- // TODO: default file?
- input.setText(Environment.getExternalStorageDirectory() + "/secexport.asc");
- input.setOnKeyListener(new OnKeyListener() {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // TODO: this doesn't actually work yet
- // If the event is a key-down event on the "enter"
- // button
- if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
- (keyCode == KeyEvent.KEYCODE_ENTER)) {
- try {
- ((AlertDialog) v.getParent())
- .getButton(AlertDialog.BUTTON_POSITIVE)
- .performClick();
- } catch (ClassCastException e) {
- // don't do anything if we're not in that dialog
- }
- return true;
- }
- return false;
- }
- });
- alert.setView(input);
+ final int thisDialogId = (singleKeyExport ? Id.dialog.export_key : Id.dialog.export_keys);
- alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
+ return FileDialog.build(this, title,
+ getString(R.string.specifyFileToExportSecretKeysTo),
+ mExportFilename,
+ new FileDialog.OnClickListener() {
+
+ @Override
+ public void onOkClick(String filename) {
removeDialog(thisDialogId);
- mExportFilename = input.getText().toString();
+ mExportFilename = filename;
exportKeys();
}
- });
- alert.setNegativeButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
+ @Override
+ public void onCancelClick() {
removeDialog(thisDialogId);
}
- });
- return alert.create();
+ },
+ getString(R.string.filemanager_titleSave),
+ getString(R.string.filemanager_btnSave),
+ Id.request.filename);
}
- case DIALOG_IMPORTING: {
- mProgressDialog = new ProgressDialog(this);
- mProgressDialog.setMessage("importing...");
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setCancelable(false);
- return mProgressDialog;
- }
-
- case DIALOG_EXPORTING: {
- mProgressDialog = new ProgressDialog(this);
- mProgressDialog.setMessage("exporting...");
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setCancelable(false);
- return mProgressDialog;
- }
-
- case AskForSecretKeyPassPhrase.DIALOG_PASS_PHRASE: {
+ case Id.dialog.pass_phrase: {
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(mSelectedItem);
long keyId = keyRing.getSecretKey().getKeyID();
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
}
+
+ default: {
+ return super.onCreateDialog(id);
+ }
+ }
+ }
+
+ public void checkPassPhraseAndEdit() {
+ PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(mSelectedItem);
+ long keyId = keyRing.getSecretKey().getKeyID();
+ String passPhrase = Apg.getCachedPassPhrase(keyId);
+ if (passPhrase == null) {
+ showDialog(Id.dialog.pass_phrase);
+ } else {
+ Apg.setEditPassPhrase(passPhrase);
+ editKey();
}
- return super.onCreateDialog(id);
}
- public void passPhraseCallback(String passPhrase) {
- Apg.setPassPhrase(passPhrase);
+ @Override
+ public void passPhraseCallback(long keyId, String passPhrase) {
+ super.passPhraseCallback(keyId, passPhrase);
+ Apg.setEditPassPhrase(passPhrase);
editKey();
}
private void createKey() {
+ Apg.setEditPassPhrase("");
Intent intent = new Intent(this, EditKeyActivity.class);
- startActivityForResult(intent, CREATE_SECRET_KEY);
+ startActivityForResult(intent, Id.message.create_key);
}
private void editKey() {
@@ -484,56 +299,74 @@ public class SecretKeyListActivity extends ExpandableListActivity long keyId = keyRing.getSecretKey().getKeyID();
Intent intent = new Intent(this, EditKeyActivity.class);
intent.putExtra("keyId", keyId);
- startActivityForResult(intent, EDIT_SECRET_KEY);
+ startActivityForResult(intent, Id.message.edit_key);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
- case CREATE_SECRET_KEY: // intentionally no break
- case EDIT_SECRET_KEY: {
+ case Id.message.create_key: // intentionally no break
+ case Id.message.edit_key: {
if (resultCode == RESULT_OK) {
refreshList();
}
break;
}
- default:
+ case Id.request.filename: {
+ if (resultCode == RESULT_OK && data != null) {
+ String filename = data.getDataString();
+ if (filename != null) {
+ // Get rid of URI prefix:
+ if (filename.startsWith("file://")) {
+ filename = filename.substring(7);
+ }
+ // replace %20 and so on
+ filename = Uri.decode(filename);
+
+ FileDialog.setFilename(filename);
+ }
+
+ }
+ return;
+ }
+
+ default: {
break;
+ }
}
super.onActivityResult(requestCode, resultCode, data);
}
public void importKeys() {
- showDialog(DIALOG_IMPORTING);
- mTask = TASK_IMPORT;
- mRunningThread = new Thread(this);
- mRunningThread.start();
+ showDialog(Id.dialog.importing);
+ mTask = Id.task.import_keys;
+ startThread();
}
public void exportKeys() {
- showDialog(DIALOG_EXPORTING);
- mTask = TASK_EXPORT;
- mRunningThread = new Thread(this);
- mRunningThread.start();
+ showDialog(Id.dialog.exporting);
+ mTask = Id.task.export_keys;
+ startThread();
}
+ @Override
public void run() {
String error = null;
Bundle data = new Bundle();
Message msg = new Message();
String filename = null;
- if (mTask == TASK_IMPORT) {
+ if (mTask == Id.task.import_keys) {
filename = mImportFilename;
} else {
filename = mExportFilename;
}
try {
- if (mTask == TASK_IMPORT) {
- data = Apg.importKeyRings(this, Apg.TYPE_SECRET, filename, this);
+ if (mTask == Id.task.import_keys) {
+ data = Apg.importKeyRings(this, Id.type.secret_key, filename, this);
} else {
Vector<Object> keys = new Vector<Object>();
if (mSelectedItem == -1) {
@@ -546,7 +379,7 @@ public class SecretKeyListActivity extends ExpandableListActivity data = Apg.exportKeyRings(this, keys, filename, this);
}
} catch (FileNotFoundException e) {
- error = "file '" + filename + "' not found";
+ error = getString(R.string.error_fileNotFound);
} catch (IOException e) {
error = e.getMessage();
} catch (PGPException e) {
@@ -555,10 +388,10 @@ public class SecretKeyListActivity extends ExpandableListActivity error = e.getMessage();
}
- if (mTask == TASK_IMPORT) {
- data.putInt("type", MESSAGE_IMPORT_DONE);
+ if (mTask == Id.task.import_keys) {
+ data.putInt("type", Id.message.import_done);
} else {
- data.putInt("type", MESSAGE_EXPORT_DONE);
+ data.putInt("type", Id.message.export_done);
}
if (error != null) {
@@ -566,7 +399,7 @@ public class SecretKeyListActivity extends ExpandableListActivity }
msg.setData(data);
- mHandler.sendMessage(msg);
+ sendMessage(msg);
}
private void deleteKey(int index) {
@@ -576,11 +409,77 @@ public class SecretKeyListActivity extends ExpandableListActivity }
private void refreshList() {
- ((SecretKeyListAdapter) getExpandableListAdapter())
- .notifyDataSetChanged();
+ ((SecretKeyListAdapter) mList.getExpandableListAdapter()).notifyDataSetChanged();
+ }
+
+ @Override
+ public void doneCallback(Message msg) {
+ super.doneCallback(msg);
+
+ Bundle data = msg.getData();
+ if (data != null) {
+ int type = data.getInt("type");
+ switch (type) {
+ case Id.message.import_done: {
+ removeDialog(Id.dialog.importing);
+
+ String error = data.getString("error");
+ if (error != null) {
+ Toast.makeText(SecretKeyListActivity.this,
+ getString(R.string.errorMessage, data.getString("error")),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ int added = data.getInt("added");
+ int updated = data.getInt("updated");
+ String message;
+ if (added > 0 && updated > 0) {
+ message = getString(R.string.keysAddedAndUpdated, added, updated);
+ } else if (added > 0) {
+ message = getString(R.string.keysAdded, added);
+ } else if (updated > 0) {
+ message = getString(R.string.keysUpdated, updated);
+ } else {
+ message = getString(R.string.noKeysAddedOrUpdated);
+ }
+ Toast.makeText(SecretKeyListActivity.this, message,
+ Toast.LENGTH_SHORT).show();
+ }
+ refreshList();
+ break;
+ }
+
+ case Id.message.export_done: {
+ removeDialog(Id.dialog.exporting);
+
+ String error = data.getString("error");
+ if (error != null) {
+ Toast.makeText(SecretKeyListActivity.this,
+ getString(R.string.errorMessage, data.getString("error")),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ int exported = data.getInt("exported");
+ String message;
+ if (exported == 1) {
+ message = getString(R.string.keyExported);
+ } else if (exported > 0) {
+ message = getString(R.string.keysExported);
+ } else{
+ message = getString(R.string.noKeysExported);
+ }
+ Toast.makeText(SecretKeyListActivity.this, message,
+ Toast.LENGTH_SHORT).show();
+ }
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+ }
}
- private class SecretKeyListAdapter extends BaseExpandableListAdapter {
+ private static class SecretKeyListAdapter extends BaseExpandableListAdapter {
private LayoutInflater mInflater;
private class KeyChild {
@@ -679,9 +578,9 @@ public class SecretKeyListActivity extends ExpandableListActivity view = mInflater.inflate(R.layout.key_list_group_item, null);
view.setBackgroundResource(android.R.drawable.list_selector_background);
- TextView mainUserId = (TextView) view.findViewById(R.id.main_user_id);
+ TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
mainUserId.setText("");
- TextView mainUserIdRest = (TextView) view.findViewById(R.id.main_user_id_rest);
+ TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
mainUserIdRest.setText("");
String userId = Apg.getMainUserId(key);
@@ -695,7 +594,7 @@ public class SecretKeyListActivity extends ExpandableListActivity }
if (mainUserId.getText().length() == 0) {
- mainUserId.setText(R.string.unknown_user_id);
+ mainUserId.setText(R.string.unknownUserId);
}
if (mainUserIdRest.getText().length() == 0) {
@@ -723,22 +622,22 @@ public class SecretKeyListActivity extends ExpandableListActivity view = mInflater.inflate(R.layout.key_list_child_item_sub_key, null);
}
- TextView keyId = (TextView) view.findViewById(R.id.key_id);
+ TextView keyId = (TextView) view.findViewById(R.id.keyId);
String keyIdStr = Long.toHexString(key.getKeyID() & 0xffffffffL);
while (keyIdStr.length() < 8) {
keyIdStr = "0" + keyIdStr;
}
keyId.setText(keyIdStr);
- TextView keyDetails = (TextView) view.findViewById(R.id.key_details);
+ TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
String algorithmStr = Apg.getAlgorithmInfo(key);
keyDetails.setText("(" + algorithmStr + ")");
- ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encrypt_key);
+ ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
if (!Apg.isEncryptionKey(key)) {
encryptIcon.setVisibility(View.GONE);
}
- ImageView signIcon = (ImageView) view.findViewById(R.id.ic_sign_key);
+ ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
if (!Apg.isSigningKey(key)) {
signIcon.setVisibility(View.GONE);
}
@@ -747,7 +646,7 @@ public class SecretKeyListActivity extends ExpandableListActivity case KeyChild.USER_ID: {
view = mInflater.inflate(R.layout.key_list_child_item_user_id, null);
- TextView userId = (TextView) view.findViewById(R.id.user_id);
+ TextView userId = (TextView) view.findViewById(R.id.userId);
userId.setText(child.userId);
break;
}
diff --git a/src/org/thialfihar/android/apg/SelectPublicKeyListActivity.java b/src/org/thialfihar/android/apg/SelectPublicKeyListActivity.java index 551d9508e..fbb0b6fe0 100644 --- a/src/org/thialfihar/android/apg/SelectPublicKeyListActivity.java +++ b/src/org/thialfihar/android/apg/SelectPublicKeyListActivity.java @@ -16,40 +16,27 @@ package org.thialfihar.android.apg; -import java.text.DateFormat; import java.util.Collections; -import java.util.Date; import java.util.Vector; import org.bouncycastle2.openpgp.PGPPublicKey; import org.bouncycastle2.openpgp.PGPPublicKeyRing; -import org.thialfihar.android.apg.utils.IterableIterator; -import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.view.View.OnClickListener; -import android.widget.BaseAdapter; import android.widget.Button; -import android.widget.CheckBox; import android.widget.ListView; -import android.widget.TextView; -public class SelectPublicKeyListActivity extends Activity { - protected Vector<PGPPublicKeyRing> mKeyRings; - protected LayoutInflater mInflater; +public class SelectPublicKeyListActivity extends BaseActivity { protected Intent mIntent; protected ListView mList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + setContentView(R.layout.select_public_key); // fill things mIntent = getIntent(); @@ -58,17 +45,18 @@ public class SelectPublicKeyListActivity extends Activity { selectedKeyIds = mIntent.getExtras().getLongArray("selection"); } - Apg.initialize(this); - mKeyRings = (Vector<PGPPublicKeyRing>) Apg.getPublicKeyRings().clone(); - Collections.sort(mKeyRings, new Apg.PublicKeySorter()); + mList = (ListView) findViewById(R.id.list); + // needed in Android 1.5, where the XML attribute gets ignored + mList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - setContentView(R.layout.select_public_key); + Vector<PGPPublicKeyRing> keyRings = + (Vector<PGPPublicKeyRing>) Apg.getPublicKeyRings().clone(); + Collections.sort(keyRings, new Apg.PublicKeySorter()); + mList.setAdapter(new SelectPublicKeyListAdapter(mList, keyRings)); - mList = (ListView) findViewById(R.id.list); - mList.setAdapter(new PublicKeyListAdapter(this)); if (selectedKeyIds != null) { - for (int i = 0; i < mKeyRings.size(); ++i) { - PGPPublicKeyRing keyRing = mKeyRings.get(i); + for (int i = 0; i < keyRings.size(); ++i) { + PGPPublicKeyRing keyRing = keyRings.get(i); PGPPublicKey key = Apg.getMasterKey(keyRing); if (key == null) { continue; @@ -122,138 +110,4 @@ public class SelectPublicKeyListActivity extends Activity { setResult(RESULT_OK, data); finish(); } - - private class PublicKeyListAdapter extends BaseAdapter { - public PublicKeyListAdapter(Context context) { - } - - @Override - public boolean isEnabled(int position) { - PGPPublicKeyRing keyRing = mKeyRings.get(position); - - if (Apg.getMasterKey(keyRing) == null) { - return false; - } - - Vector<PGPPublicKey> encryptKeys = Apg.getUsableEncryptKeys(keyRing); - if (encryptKeys.size() == 0) { - return false; - } - - return true; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public int getCount() { - return mKeyRings.size(); - } - - @Override - public Object getItem(int position) { - return mKeyRings.get(position); - } - - @Override - public long getItemId(int position) { - PGPPublicKeyRing keyRing = mKeyRings.get(position); - PGPPublicKey key = Apg.getMasterKey(keyRing); - if (key != null) { - return key.getKeyID(); - } - - return 0; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View view = mInflater.inflate(R.layout.select_public_key_item, null); - boolean enabled = isEnabled(position); - - PGPPublicKeyRing keyRing = mKeyRings.get(position); - PGPPublicKey key = null; - for (PGPPublicKey tKey : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) { - if (tKey.isMasterKey()) { - key = tKey; - break; - } - } - - Vector<PGPPublicKey> encryptKeys = Apg.getEncryptKeys(keyRing); - Vector<PGPPublicKey> usableKeys = Apg.getUsableEncryptKeys(keyRing); - - TextView mainUserId = (TextView) view.findViewById(R.id.main_user_id); - mainUserId.setText(R.string.unknown_user_id); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.main_user_id_rest); - mainUserIdRest.setText(""); - TextView keyId = (TextView) view.findViewById(R.id.key_id); - keyId.setText("<no key>"); - TextView creation = (TextView) view.findViewById(R.id.creation); - creation.setText("-"); - TextView expiry = (TextView) view.findViewById(R.id.expiry); - expiry.setText("no expire"); - TextView status = (TextView) view.findViewById(R.id.status); - status.setText("???"); - - if (key != null) { - String userId = Apg.getMainUserId(key); - if (userId != null) { - String chunks[] = userId.split(" <", 2); - userId = chunks[0]; - if (chunks.length > 1) { - mainUserIdRest.setText("<" + chunks[1]); - } - mainUserId.setText(userId); - } - - keyId.setText("" + Long.toHexString(key.getKeyID() & 0xffffffffL)); - } - - if (mainUserIdRest.getText().length() == 0) { - mainUserIdRest.setVisibility(View.GONE); - } - - PGPPublicKey timespanKey = key; - if (usableKeys.size() > 0) { - timespanKey = usableKeys.get(0); - status.setText("can encrypt"); - } else if (encryptKeys.size() > 0) { - timespanKey = encryptKeys.get(0); - Date now = new Date(); - if (now.compareTo(Apg.getCreationDate(timespanKey)) > 0) { - status.setText("not valid"); - } else { - status.setText("expired"); - } - } else { - status.setText("no key"); - } - - creation.setText(DateFormat.getDateInstance().format(Apg.getCreationDate(timespanKey))); - Date expiryDate = Apg.getExpiryDate(timespanKey); - if (expiryDate != null) { - expiry.setText(DateFormat.getDateInstance().format(expiryDate)); - } - - status.setText(status.getText() + " "); - - CheckBox selected = (CheckBox) view.findViewById(R.id.selected); - selected.setChecked(mList.isItemChecked(position)); - - view.setEnabled(enabled); - mainUserId.setEnabled(enabled); - mainUserIdRest.setEnabled(enabled); - keyId.setEnabled(enabled); - creation.setEnabled(enabled); - expiry.setEnabled(enabled); - selected.setEnabled(enabled); - status.setEnabled(enabled); - - return view; - } - } }
\ No newline at end of file diff --git a/src/org/thialfihar/android/apg/SelectPublicKeyListAdapter.java b/src/org/thialfihar/android/apg/SelectPublicKeyListAdapter.java new file mode 100644 index 000000000..1b0b82fd8 --- /dev/null +++ b/src/org/thialfihar/android/apg/SelectPublicKeyListAdapter.java @@ -0,0 +1,186 @@ +/*
+ * Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.thialfihar.android.apg;
+
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.Vector;
+
+import org.bouncycastle2.openpgp.PGPPublicKey;
+import org.bouncycastle2.openpgp.PGPPublicKeyRing;
+import org.thialfihar.android.apg.utils.IterableIterator;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.CheckBox;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class SelectPublicKeyListAdapter extends BaseAdapter {
+ protected Vector<PGPPublicKeyRing> mKeyRings;
+ protected LayoutInflater mInflater;
+ protected ListView mParent;
+
+ public SelectPublicKeyListAdapter(ListView parent,
+ Vector<PGPPublicKeyRing> keyRings) {
+ setKeyRings(keyRings);
+ mParent = parent;
+ mInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ public void setKeyRings(Vector<PGPPublicKeyRing> keyRings) {
+ mKeyRings = keyRings;
+ notifyDataSetChanged();
+ }
+
+ public Vector<PGPPublicKeyRing> getKeyRings() {
+ return mKeyRings;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ PGPPublicKeyRing keyRing = mKeyRings.get(position);
+
+ if (Apg.getMasterKey(keyRing) == null) {
+ return false;
+ }
+
+ Vector<PGPPublicKey> encryptKeys = Apg.getUsableEncryptKeys(keyRing);
+ if (encryptKeys.size() == 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public int getCount() {
+ return mKeyRings.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mKeyRings.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ PGPPublicKeyRing keyRing = mKeyRings.get(position);
+ PGPPublicKey key = Apg.getMasterKey(keyRing);
+ if (key != null) {
+ return key.getKeyID();
+ }
+
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = mInflater.inflate(R.layout.select_public_key_item, null);
+ boolean enabled = isEnabled(position);
+
+ PGPPublicKeyRing keyRing = mKeyRings.get(position);
+ PGPPublicKey key = null;
+ for (PGPPublicKey tKey : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
+ if (tKey.isMasterKey()) {
+ key = tKey;
+ break;
+ }
+ }
+
+ Vector<PGPPublicKey> encryptKeys = Apg.getEncryptKeys(keyRing);
+ Vector<PGPPublicKey> usableKeys = Apg.getUsableEncryptKeys(keyRing);
+
+ TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
+ mainUserId.setText(R.string.unknownUserId);
+ TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
+ mainUserIdRest.setText("");
+ TextView keyId = (TextView) view.findViewById(R.id.keyId);
+ keyId.setText(R.string.noKey);
+ TextView creation = (TextView) view.findViewById(R.id.creation);
+ creation.setText(R.string.noDate);
+ TextView expiry = (TextView) view.findViewById(R.id.expiry);
+ expiry.setText(R.string.noExpiry);
+ TextView status = (TextView) view.findViewById(R.id.status);
+ status.setText(R.string.unknownStatus);
+
+ if (key != null) {
+ String userId = Apg.getMainUserId(key);
+ if (userId != null) {
+ String chunks[] = userId.split(" <", 2);
+ userId = chunks[0];
+ if (chunks.length > 1) {
+ mainUserIdRest.setText("<" + chunks[1]);
+ }
+ mainUserId.setText(userId);
+ }
+
+ keyId.setText("" + Long.toHexString(key.getKeyID() & 0xffffffffL));
+ }
+
+ if (mainUserIdRest.getText().length() == 0) {
+ mainUserIdRest.setVisibility(View.GONE);
+ }
+
+ PGPPublicKey timespanKey = key;
+ if (usableKeys.size() > 0) {
+ timespanKey = usableKeys.get(0);
+ status.setText(R.string.canEncrypt);
+ } else if (encryptKeys.size() > 0) {
+ timespanKey = encryptKeys.get(0);
+ Date now = new Date();
+ if (now.compareTo(Apg.getCreationDate(timespanKey)) > 0) {
+ status.setText(R.string.notValid);
+ } else {
+ status.setText(R.string.expired);
+ }
+ } else {
+ status.setText(R.string.noKey);
+ }
+
+ creation.setText(DateFormat.getDateInstance().format(Apg.getCreationDate(timespanKey)));
+ Date expiryDate = Apg.getExpiryDate(timespanKey);
+ if (expiryDate != null) {
+ expiry.setText(DateFormat.getDateInstance().format(expiryDate));
+ }
+
+ status.setText(status.getText() + " ");
+
+ CheckBox selected = (CheckBox) view.findViewById(R.id.selected);
+
+ selected.setChecked(mParent.isItemChecked(position));
+
+ view.setEnabled(enabled);
+ mainUserId.setEnabled(enabled);
+ mainUserIdRest.setEnabled(enabled);
+ keyId.setEnabled(enabled);
+ creation.setEnabled(enabled);
+ expiry.setEnabled(enabled);
+ selected.setEnabled(enabled);
+ status.setEnabled(enabled);
+
+ return view;
+ }
+}
diff --git a/src/org/thialfihar/android/apg/SelectSecretKeyListActivity.java b/src/org/thialfihar/android/apg/SelectSecretKeyListActivity.java index da7094c53..b6811d6e3 100644 --- a/src/org/thialfihar/android/apg/SelectSecretKeyListActivity.java +++ b/src/org/thialfihar/android/apg/SelectSecretKeyListActivity.java @@ -25,7 +25,6 @@ import org.bouncycastle2.openpgp.PGPSecretKey; import org.bouncycastle2.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.utils.IterableIterator; -import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -38,7 +37,7 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; -public class SelectSecretKeyListActivity extends Activity { +public class SelectSecretKeyListActivity extends BaseActivity { protected Vector<PGPSecretKeyRing> mKeyRings; protected LayoutInflater mInflater; protected Intent mIntent; @@ -55,8 +54,6 @@ public class SelectSecretKeyListActivity extends Activity { // fill things mIntent = getIntent(); - Apg.initialize(this); - mKeyRings = (Vector<PGPSecretKeyRing>) Apg.getSecretKeyRings().clone(); Collections.sort(mKeyRings, new Apg.SecretKeySorter()); @@ -137,18 +134,18 @@ public class SelectSecretKeyListActivity extends Activity { } } - TextView mainUserId = (TextView) view.findViewById(R.id.main_user_id); - mainUserId.setText(R.string.unknown_user_id); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.main_user_id_rest); + TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); + mainUserId.setText(R.string.unknownUserId); + TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); mainUserIdRest.setText(""); - TextView keyId = (TextView) view.findViewById(R.id.key_id); - keyId.setText("<no key>"); + TextView keyId = (TextView) view.findViewById(R.id.keyId); + keyId.setText(R.string.noKey); TextView creation = (TextView) view.findViewById(R.id.creation); - creation.setText(""); + creation.setText(R.string.noDate); TextView expiry = (TextView) view.findViewById(R.id.expiry); - expiry.setText(""); + expiry.setText(R.string.noExpiry); TextView status = (TextView) view.findViewById(R.id.status); - status.setText("???"); + status.setText(R.string.unknownStatus); if (key != null) { String userId = Apg.getMainUserId(key); @@ -174,17 +171,17 @@ public class SelectSecretKeyListActivity extends Activity { PGPSecretKey timespanKey = key; if (usableKeys.size() > 0) { timespanKey = usableKeys.get(0); - status.setText("can sign"); + status.setText(R.string.canSign); } else if (signingKeys.size() > 0) { timespanKey = signingKeys.get(0); Date now = new Date(); if (now.compareTo(Apg.getCreationDate(timespanKey)) > 0) { - status.setText("not valid"); + status.setText(R.string.notValid); } else { - status.setText("expired"); + status.setText(R.string.expired); } } else { - status.setText("no key"); + status.setText(R.string.noKey); } creation.setText(DateFormat.getDateInstance().format(Apg.getCreationDate(timespanKey))); diff --git a/src/org/thialfihar/android/apg/provider/DataProvider.java b/src/org/thialfihar/android/apg/provider/DataProvider.java index 0a6a814e4..fbc1be047 100644 --- a/src/org/thialfihar/android/apg/provider/DataProvider.java +++ b/src/org/thialfihar/android/apg/provider/DataProvider.java @@ -115,14 +115,7 @@ public class DataProvider extends ContentProvider { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - int currentVersion = oldVersion; - while (currentVersion < newVersion) { - switch (currentVersion) { - default: { - break; - } - } - } + // TODO: upgrade db if necessary, and do that in a clever way } } diff --git a/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java b/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java index 263f34675..bc38fba4c 100644 --- a/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java +++ b/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java @@ -22,8 +22,10 @@ import java.util.Date; import java.util.GregorianCalendar;
import java.util.Vector;
+import org.bouncycastle2.openpgp.PGPPublicKey;
import org.bouncycastle2.openpgp.PGPSecretKey;
import org.thialfihar.android.apg.Apg;
+import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.utils.Choice;
@@ -65,26 +67,6 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { }
};
- public static class AlgorithmChoice extends Choice {
- public static final int DSA = 1;
- public static final int ELGAMAL = 2;
- public static final int RSA = 3;
-
- public AlgorithmChoice(int id, String name) {
- super(id, name);
- }
- }
-
- public static class UsageChoice extends Choice {
- public static final int SIGN_ONLY = 1;
- public static final int ENCRYPT_ONLY = 2;
- public static final int SIGN_AND_ENCRYPT = 3;
-
- public UsageChoice(int id, String name) {
- super(id, name);
- }
- }
-
public KeyEditor(Context context) {
super(context);
}
@@ -99,26 +81,25 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { setAlwaysDrawnWithCacheEnabled(true);
mAlgorithm = (TextView) findViewById(R.id.algorithm);
- mKeyId = (TextView) findViewById(R.id.key_id);
+ mKeyId = (TextView) findViewById(R.id.keyId);
mCreationDate = (TextView) findViewById(R.id.creation);
mExpiryDateButton = (Button) findViewById(R.id.expiry);
mUsage = (Spinner) findViewById(R.id.usage);
- KeyEditor.UsageChoice choices[] = {
- new KeyEditor.UsageChoice(KeyEditor.UsageChoice.SIGN_ONLY,
- getResources().getString(R.string.sign_only)),
- new KeyEditor.UsageChoice(KeyEditor.UsageChoice.ENCRYPT_ONLY,
- getResources().getString(R.string.encrypt_only)),
- new KeyEditor.UsageChoice(KeyEditor.UsageChoice.SIGN_AND_ENCRYPT,
- getResources().getString(R.string.sign_and_encrypt)),
+ Choice choices[] = {
+ new Choice(Id.choice.usage.sign_only,
+ getResources().getString(R.string.choice_signOnly)),
+ new Choice(Id.choice.usage.encrypt_only,
+ getResources().getString(R.string.choice_encryptOnly)),
+ new Choice(Id.choice.usage.sign_and_encrypt,
+ getResources().getString(R.string.choice_signAndEncrypt)),
};
- ArrayAdapter<KeyEditor.UsageChoice> adapter =
- new ArrayAdapter<KeyEditor.UsageChoice>(getContext(),
- android.R.layout.simple_spinner_item,
- choices);
+ ArrayAdapter<Choice> adapter =
+ new ArrayAdapter<Choice>(getContext(),
+ android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mUsage.setAdapter(adapter);
- mDeleteButton = (ImageButton) findViewById(R.id.edit_delete);
+ mDeleteButton = (ImageButton) findViewById(R.id.delete);
mDeleteButton.setOnClickListener(this);
setExpiryDate(null);
@@ -137,7 +118,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { date.get(Calendar.MONTH),
date.get(Calendar.DAY_OF_MONTH));
dialog.setCancelable(true);
- dialog.setButton(Dialog.BUTTON_NEGATIVE, "None",
+ dialog.setButton(Dialog.BUTTON_NEGATIVE,
+ getContext().getString(R.string.btn_noDate),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
setExpiryDate(null);
@@ -169,31 +151,43 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { }
mKeyId.setText(keyId1Str + " " + keyId2Str);
- Vector<KeyEditor.UsageChoice> choices = new Vector<KeyEditor.UsageChoice>();
- choices.add(new KeyEditor.UsageChoice(KeyEditor.UsageChoice.SIGN_ONLY,
- getResources().getString(R.string.sign_only)));
+ Vector<Choice> choices = new Vector<Choice>();
+ boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT);
+ if (!isElGamalKey) {
+ choices.add(new Choice(Id.choice.usage.sign_only,
+ getResources().getString(R.string.choice_signOnly)));
+ }
if (!mIsMasterKey) {
- choices.add(new KeyEditor.UsageChoice(KeyEditor.UsageChoice.ENCRYPT_ONLY,
- getResources().getString(R.string.encrypt_only)));
+ choices.add(new Choice(Id.choice.usage.encrypt_only,
+ getResources().getString(R.string.choice_encryptOnly)));
+ }
+ if (!isElGamalKey) {
+ choices.add(new Choice(Id.choice.usage.sign_and_encrypt,
+ getResources().getString(R.string.choice_signAndEncrypt)));
}
- choices.add(new KeyEditor.UsageChoice(KeyEditor.UsageChoice.SIGN_AND_ENCRYPT,
- getResources().getString(R.string.sign_and_encrypt)));
- ArrayAdapter<KeyEditor.UsageChoice> adapter =
- new ArrayAdapter<KeyEditor.UsageChoice>(getContext(),
- android.R.layout.simple_spinner_item,
- choices);
+ ArrayAdapter<Choice> adapter =
+ new ArrayAdapter<Choice>(getContext(),
+ android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mUsage.setAdapter(adapter);
+ int selectId = 0;
if (Apg.isEncryptionKey(key)) {
if (Apg.isSigningKey(key)) {
- mUsage.setSelection(2);
+ selectId = Id.choice.usage.sign_and_encrypt;
} else {
- mUsage.setSelection(1);
+ selectId = Id.choice.usage.encrypt_only;
}
} else {
- mUsage.setSelection(0);
+ selectId = Id.choice.usage.sign_only;
+ }
+
+ for (int i = 0; i < choices.size(); ++i) {
+ if (choices.get(i).getId() == selectId) {
+ mUsage.setSelection(i);
+ break;
+ }
}
GregorianCalendar cal = new GregorianCalendar();
@@ -242,7 +236,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { return mExpiryDate;
}
- public UsageChoice getUsage() {
- return (UsageChoice) mUsage.getSelectedItem();
+ public int getUsage() {
+ return ((Choice) mUsage.getSelectedItem()).getId();
}
}
diff --git a/src/org/thialfihar/android/apg/ui/widget/SectionView.java b/src/org/thialfihar/android/apg/ui/widget/SectionView.java index b257da409..cc1410c26 100644 --- a/src/org/thialfihar/android/apg/ui/widget/SectionView.java +++ b/src/org/thialfihar/android/apg/ui/widget/SectionView.java @@ -25,8 +25,10 @@ import java.util.Vector; import org.bouncycastle2.openpgp.PGPException;
import org.bouncycastle2.openpgp.PGPSecretKey;
import org.thialfihar.android.apg.Apg;
+import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
+import org.thialfihar.android.apg.utils.Choice;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -48,16 +50,13 @@ import android.widget.TextView; import android.widget.Toast;
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Runnable {
- public static final int TYPE_USER_ID = 1;
- public static final int TYPE_KEY = 2;
-
private LayoutInflater mInflater;
private View mAdd;
private ViewGroup mEditors;
private TextView mTitle;
private int mType = 0;
- private KeyEditor.AlgorithmChoice mNewKeyAlgorithmChoice;
+ private Choice mNewKeyAlgorithmChoice;
private int mNewKeySize;
volatile private PGPSecretKey mNewKey;
@@ -80,7 +79,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor String error = data.getString("error");
if (error != null) {
Toast.makeText(getContext(),
- "Error: " + error,
+ getContext().getString(R.string.errorMessage, error),
Toast.LENGTH_SHORT).show();
}
@@ -114,12 +113,12 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor public void setType(int type) {
mType = type;
switch (type) {
- case TYPE_USER_ID: {
+ case Id.type.user_id: {
mTitle.setText(R.string.section_userIds);
break;
}
- case TYPE_KEY: {
+ case Id.type.key: {
mTitle.setText(R.string.section_keys);
break;
}
@@ -161,7 +160,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor /** {@inheritDoc} */
public void onClick(View v) {
switch (mType) {
- case TYPE_USER_ID: {
+ case Id.type.user_id: {
UserIdEditor view =
(UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item,
mEditors, false);
@@ -173,32 +172,37 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor break;
}
- case TYPE_KEY: {
+ case Id.type.key: {
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
View view = mInflater.inflate(R.layout.create_key, null);
dialog.setView(view);
- dialog.setTitle("Create Key");
+ dialog.setTitle(R.string.title_createKey);
+ dialog.setMessage(R.string.keyCreationElGamalInfo);
+
+ boolean wouldBeMasterKey = (mEditors.getChildCount() == 0);
final Spinner algorithm = (Spinner) view.findViewById(R.id.algorithm);
- KeyEditor.AlgorithmChoice choices[] = {
- new KeyEditor.AlgorithmChoice(KeyEditor.AlgorithmChoice.DSA,
- getResources().getString(R.string.dsa)),
- /*new KeyEditor.AlgorithmChoice(KeyEditor.AlgorithmChoice.ELGAMAL,
- getResources().getString(R.string.elgamal)),*/
- new KeyEditor.AlgorithmChoice(KeyEditor.AlgorithmChoice.RSA,
- getResources().getString(R.string.rsa)),
- };
- ArrayAdapter<KeyEditor.AlgorithmChoice> adapter =
- new ArrayAdapter<KeyEditor.AlgorithmChoice>(
- getContext(),
- android.R.layout.simple_spinner_item,
- choices);
+ Vector<Choice> choices = new Vector<Choice>();
+ choices.add(new Choice(Id.choice.algorithm.dsa,
+ getResources().getString(R.string.dsa)));
+ if (!wouldBeMasterKey) {
+ choices.add(new Choice(Id.choice.algorithm.elgamal,
+ getResources().getString(R.string.elgamal)));
+ }
+
+ choices.add(new Choice(Id.choice.algorithm.rsa,
+ getResources().getString(R.string.rsa)));
+
+ ArrayAdapter<Choice> adapter =
+ new ArrayAdapter<Choice>(getContext(),
+ android.R.layout.simple_spinner_item,
+ choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
algorithm.setAdapter(adapter);
// make RSA the default
- for (int i = 0; i < choices.length; ++i) {
- if (choices[i].getId() == KeyEditor.AlgorithmChoice.RSA) {
+ for (int i = 0; i < choices.size(); ++i) {
+ if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
algorithm.setSelection(i);
break;
}
@@ -217,8 +221,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor mNewKeySize = 0;
}
- mNewKeyAlgorithmChoice =
- (KeyEditor.AlgorithmChoice) algorithm.getSelectedItem();
+ mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
createKey();
}
});
@@ -244,7 +247,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor }
public void setUserIds(Vector<String> list) {
- if (mType != TYPE_USER_ID) {
+ if (mType != Id.type.user_id) {
return;
}
@@ -264,7 +267,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor }
public void setKeys(Vector<PGPSecretKey> list) {
- if (mType != TYPE_KEY) {
+ if (mType != Id.type.key) {
return;
}
@@ -283,7 +286,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor private void createKey() {
mProgressDialog = new ProgressDialog(getContext());
- mProgressDialog.setMessage("Generating key, this can take a while...");
+ mProgressDialog.setMessage(getContext().getString(R.string.progress_generating));
mProgressDialog.setCancelable(false);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.show();
@@ -294,7 +297,18 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor public void run() {
String error = null;
try {
- mNewKey = Apg.createKey(mNewKeyAlgorithmChoice, mNewKeySize, Apg.getPassPhrase());
+ PGPSecretKey masterKey = null;
+ String passPhrase;
+ if (mEditors.getChildCount() > 0) {
+ masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
+ passPhrase = Apg.getCachedPassPhrase(masterKey.getKeyID());
+ } else {
+ passPhrase = "";
+ }
+ mNewKey = Apg.createKey(getContext(),
+ mNewKeyAlgorithmChoice.getId(),
+ mNewKeySize, passPhrase,
+ masterKey);
} catch (NoSuchProviderException e) {
error = e.getMessage();
} catch (NoSuchAlgorithmException e) {
diff --git a/src/org/thialfihar/android/apg/ui/widget/UserIdEditor.java b/src/org/thialfihar/android/apg/ui/widget/UserIdEditor.java index a7e762b4f..5d710257a 100644 --- a/src/org/thialfihar/android/apg/ui/widget/UserIdEditor.java +++ b/src/org/thialfihar/android/apg/ui/widget/UserIdEditor.java @@ -81,9 +81,9 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
- mDeleteButton = (ImageButton) findViewById(R.id.edit_delete);
+ mDeleteButton = (ImageButton) findViewById(R.id.delete);
mDeleteButton.setOnClickListener(this);
- mIsMainUserId = (RadioButton) findViewById(R.id.is_main_user_id);
+ mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId);
mIsMainUserId.setOnClickListener(this);
mName = (EditText) findViewById(R.id.name);
@@ -124,7 +124,8 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene if (email.length() > 0) {
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
if (!emailMatcher.matches()) {
- throw new InvalidEmailException("invalid email '" + email + "'");
+ throw new InvalidEmailException(
+ getContext().getString(R.string.error_invalidEmail, email));
}
}
|