diff --git a/.travis.yml b/.travis.yml index 28827f332..54db1a965 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools # Install required Android components. - - echo "y" | android update sdk -a --filter build-tools-19.0.1,android-19,platform-tools,extra-android-support,extra-android-m2repository,android-17 --no-ui --force + - echo "y" | android update sdk -a --filter build-tools-19.0.3,android-19,platform-tools,extra-android-support,extra-android-m2repository --no-ui --force install: echo "Installation done" script: gradle assemble -S -q diff --git a/OpenPGP-Keychain-API/build.gradle b/OpenPGP-Keychain-API/build.gradle index 2e41492a3..0ce5dc8c0 100644 --- a/OpenPGP-Keychain-API/build.gradle +++ b/OpenPGP-Keychain-API/build.gradle @@ -1,3 +1,3 @@ task wrapper(type: Wrapper) { gradleVersion = '1.10' -} \ No newline at end of file +} diff --git a/OpenPGP-Keychain-API/example-app/build.gradle b/OpenPGP-Keychain-API/example-app/build.gradle index 1f8854431..e7a25e689 100644 --- a/OpenPGP-Keychain-API/example-app/build.gradle +++ b/OpenPGP-Keychain-API/example-app/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.8.3' + classpath 'com.android.tools.build:gradle:0.9.0' } } @@ -13,12 +13,13 @@ apply plugin: 'android' dependencies { compile 'com.android.support:support-v4:19.0.1' - compile project(':libraries:keychain-api-library') + compile project(':libraries:openpgp-api-library') + compile project(':libraries:openkeychain-api-library') } android { compileSdkVersion 19 - buildToolsVersion "19.0.1" + buildToolsVersion "19.0.3" defaultConfig { minSdkVersion 9 diff --git a/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java b/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java index 4d143ade6..a660b1c9a 100644 --- a/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java +++ b/OpenPGP-Keychain-API/example-app/src/main/java/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java @@ -202,7 +202,7 @@ public class OpenPgpProviderActivity extends Activity { break; } case OpenPgpApi.RESULT_CODE_ERROR: { - OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERRORS); + OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); handleError(error); break; } @@ -234,7 +234,7 @@ public class OpenPgpProviderActivity extends Activity { } public void signAndEncrypt(Intent data) { - data.setAction(OpenPgpApi.ACTION_SIGN_AND_ENCTYPT); + data.setAction(OpenPgpApi.ACTION_SIGN_AND_ENCRYPT); data.putExtra(OpenPgpApi.EXTRA_USER_IDS, mEncryptUserIds.getText().toString().split(",")); data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); diff --git a/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties b/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties index 932184188..d8e0b5b29 100644 --- a/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties +++ b/OpenPGP-Keychain-API/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Feb 14 01:26:40 CET 2014 +#Thu Mar 06 22:23:44 CET 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/.gitignore b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/.gitignore similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/.gitignore rename to OpenPGP-Keychain-API/libraries/openkeychain-api-library/.gitignore diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/AndroidManifest.xml b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/AndroidManifest.xml similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/AndroidManifest.xml rename to OpenPGP-Keychain-API/libraries/openkeychain-api-library/AndroidManifest.xml diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/LICENSE b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/LICENSE similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/LICENSE rename to OpenPGP-Keychain-API/libraries/openkeychain-api-library/LICENSE diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/build.gradle similarity index 89% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle rename to OpenPGP-Keychain-API/libraries/openkeychain-api-library/build.gradle index 1d5911783..98c9a3bd6 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle +++ b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.8.3' + classpath 'com.android.tools.build:gradle:0.9.0' } } @@ -13,7 +13,7 @@ apply plugin: 'android-library' android { compileSdkVersion 19 - buildToolsVersion '19.0.1' + buildToolsVersion '19.0.3' // NOTE: We are using the old folder structure to also support Eclipse sourceSets { diff --git a/OpenPGP-Keychain-API/libraries/openkeychain-api-library/build.xml b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/build.xml new file mode 100644 index 000000000..48ebf198c --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenPGP-Keychain-API/libraries/openkeychain-api-library/proguard-project.txt b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/proguard-project.txt new file mode 100644 index 000000000..f2fe1559a --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/project.properties b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/project.properties similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/project.properties rename to OpenPGP-Keychain-API/libraries/openkeychain-api-library/project.properties diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/sufficientlysecure/keychain/api/OpenKeychainIntents.java b/OpenPGP-Keychain-API/libraries/openkeychain-api-library/src/org/sufficientlysecure/keychain/api/OpenKeychainIntents.java similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/sufficientlysecure/keychain/api/OpenKeychainIntents.java rename to OpenPGP-Keychain-API/libraries/openkeychain-api-library/src/org/sufficientlysecure/keychain/api/OpenKeychainIntents.java diff --git a/OpenPGP-Keychain-API/libraries/openpgp-api-library/.gitignore b/OpenPGP-Keychain-API/libraries/openpgp-api-library/.gitignore new file mode 100644 index 000000000..aa8bb5760 --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/.gitignore @@ -0,0 +1,29 @@ +#Android specific +bin +gen +obj +lint.xml +local.properties +release.properties +ant.properties +*.class +*.apk + +#Gradle +.gradle +build +gradle.properties + +#Maven +target +pom.xml.* + +#Eclipse +.project +.classpath +.settings +.metadata + +#IntelliJ IDEA +.idea +*.iml diff --git a/OpenPGP-Keychain-API/libraries/openpgp-api-library/AndroidManifest.xml b/OpenPGP-Keychain-API/libraries/openpgp-api-library/AndroidManifest.xml new file mode 100644 index 000000000..98cb89faa --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/AndroidManifest.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain-API/libraries/openpgp-api-library/LICENSE b/OpenPGP-Keychain-API/libraries/openpgp-api-library/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/OpenPGP-Keychain-API/libraries/openpgp-api-library/build.gradle b/OpenPGP-Keychain-API/libraries/openpgp-api-library/build.gradle new file mode 100644 index 000000000..98c9a3bd6 --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/build.gradle @@ -0,0 +1,35 @@ +// please leave this here, so this library builds on its own +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:0.9.0' + } +} + +apply plugin: 'android-library' + +android { + compileSdkVersion 19 + buildToolsVersion '19.0.3' + + // NOTE: We are using the old folder structure to also support Eclipse + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + resources.srcDirs = ['src'] + aidl.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + } + } + + // Do not abort build if lint finds errors + lintOptions { + abortOnError false + } +} diff --git a/OpenPGP-Keychain-API/libraries/openpgp-api-library/build.xml b/OpenPGP-Keychain-API/libraries/openpgp-api-library/build.xml new file mode 100644 index 000000000..48ebf198c --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenPGP-Keychain-API/libraries/openpgp-api-library/proguard-project.txt b/OpenPGP-Keychain-API/libraries/openpgp-api-library/proguard-project.txt new file mode 100644 index 000000000..f2fe1559a --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/OpenPGP-Keychain-API/libraries/openpgp-api-library/project.properties b/OpenPGP-Keychain-API/libraries/openpgp-api-library/project.properties new file mode 100644 index 000000000..91d2b0246 --- /dev/null +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-19 +android.library=true diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-hdpi/ic_action_cancel_launchersize.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-hdpi/ic_action_cancel_launchersize.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-hdpi/ic_action_cancel_launchersize.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-hdpi/ic_action_cancel_launchersize.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-hdpi/ic_action_cancel_launchersize_light.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-hdpi/ic_action_cancel_launchersize_light.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-hdpi/ic_action_cancel_launchersize_light.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-hdpi/ic_action_cancel_launchersize_light.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-mdpi/ic_action_cancel_launchersize.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-mdpi/ic_action_cancel_launchersize.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-mdpi/ic_action_cancel_launchersize.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-mdpi/ic_action_cancel_launchersize.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-mdpi/ic_action_cancel_launchersize_light.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-mdpi/ic_action_cancel_launchersize_light.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-mdpi/ic_action_cancel_launchersize_light.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-mdpi/ic_action_cancel_launchersize_light.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize_light.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize_light.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize_light.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xhdpi/ic_action_cancel_launchersize_light.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize_light.png b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize_light.png similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize_light.png rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/drawable-xxhdpi/ic_action_cancel_launchersize_light.png diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/res/values/strings.xml b/OpenPGP-Keychain-API/libraries/openpgp-api-library/res/values/strings.xml similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/res/values/strings.xml rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/res/values/strings.xml diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/IOpenPgpService.aidl similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/IOpenPgpService.aidl rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/IOpenPgpService.aidl diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/OpenPgpError.java b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/OpenPgpError.java similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/OpenPgpError.java rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/OpenPgpError.java diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java similarity index 88% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java index 431d4be24..cb220cf6d 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java @@ -38,24 +38,40 @@ public class OpenPgpSignatureResult implements Parcelable { return status; } + public void setStatus(int status) { + this.status = status; + } + public boolean isSignatureOnly() { return signatureOnly; } + public void setSignatureOnly(boolean signatureOnly) { + this.signatureOnly = signatureOnly; + } + public String getUserId() { return userId; } + public void setUserId(String userId) { + this.userId = userId; + } + public long getKeyId() { return keyId; } + public void setKeyId(long keyId) { + this.keyId = keyId; + } + public OpenPgpSignatureResult() { } public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, - boolean signatureOnly, long keyId) { + boolean signatureOnly, long keyId) { this.status = signatureStatus; this.signatureOnly = signatureOnly; this.userId = signatureUserId; diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java similarity index 64% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java index ed1a7540a..f768a1685 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java @@ -16,119 +16,146 @@ package org.openintents.openpgp.util; +import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Build; import android.os.ParcelFileDescriptor; import android.util.Log; - import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.OpenPgpError; - import java.io.InputStream; import java.io.OutputStream; public class OpenPgpApi { - //TODO: fix this documentation + public static final String TAG = "OpenPgp API"; + + public static final int API_VERSION = 2; + public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; + /** * General extras * -------------- * - * Intent extras: - * int api_version (required) - * boolean ascii_armor (request ascii armor for ouput) + * required extras: + * int EXTRA_API_VERSION (always required) * - * returned Bundle: - * int result_code (0, 1, or 2 (see OpenPgpApi)) - * OpenPgpError error (if result_code == 0) - * Intent intent (if result_code == 2) + * returned extras: + * int RESULT_CODE (RESULT_CODE_ERROR, RESULT_CODE_SUCCESS or RESULT_CODE_USER_INTERACTION_REQUIRED) + * OpenPgpError RESULT_ERROR (if RESULT_CODE == RESULT_CODE_ERROR) + * PendingIntent RESULT_INTENT (if RESULT_CODE == RESULT_CODE_USER_INTERACTION_REQUIRED) */ /** * Sign only * - * optional params: - * String passphrase (for key passphrase) + * optional extras: + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * String EXTRA_PASSPHRASE (key passphrase) */ + public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN"; /** * Encrypt * - * Intent extras: - * long[] key_ids + * required extras: + * String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT) * or - * String[] user_ids (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned) + * long[] EXTRA_KEY_IDS * * optional extras: - * String passphrase (for key passphrase) + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * String EXTRA_PASSPHRASE (key passphrase) */ + public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT"; /** * Sign and encrypt * - * Intent extras: - * same as in encrypt() + * required extras: + * String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT) + * or + * long[] EXTRA_KEY_IDS + * + * optional extras: + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * String EXTRA_PASSPHRASE (key passphrase) */ + public static final String ACTION_SIGN_AND_ENCRYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT"; /** - * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, + * Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted, * and also signed-only input. * - * returned Bundle: - * OpenPgpSignatureResult signature_result + * If OpenPgpSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY + * in addition a PendingIntent is returned via RESULT_INTENT to download missing keys. + * + * optional extras: + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * + * returned extras: + * OpenPgpSignatureResult RESULT_SIGNATURE */ + public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY"; /** - * Retrieves key ids based on given user ids (=emails) + * Get key ids based on given user ids (=emails) * - * Intent extras: - * String[] user_ids + * required extras: + * String[] EXTRA_USER_IDS * - * returned Bundle: - * long[] key_ids + * returned extras: + * long[] EXTRA_KEY_IDS */ - - public static final String TAG = "OpenPgp API"; - - public static final int API_VERSION = 2; - public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; - - public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN"; - public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT"; - public static final String ACTION_SIGN_AND_ENCTYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT"; - public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY"; - public static final String ACTION_DOWNLOAD_KEYS = "org.openintents.openpgp.action.DOWNLOAD_KEYS"; public static final String ACTION_GET_KEY_IDS = "org.openintents.openpgp.action.GET_KEY_IDS"; - /* Bundle params */ + /** + * This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key + * corresponding to the given key id in its database. + * + * It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key. + * The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver. + * + * required extras: + * long EXTRA_KEY_ID + */ + public static final String ACTION_GET_KEY = "org.openintents.openpgp.action.GET_KEY"; + + /* Intent extras */ public static final String EXTRA_API_VERSION = "api_version"; - // SIGN, ENCRYPT, SIGN_ENCRYPT, DECRYPT_VERIFY + // SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY // request ASCII Armor for output // OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) public static final String EXTRA_REQUEST_ASCII_ARMOR = "ascii_armor"; - // ENCRYPT, SIGN_ENCRYPT + // ENCRYPT, SIGN_AND_ENCRYPT public static final String EXTRA_USER_IDS = "user_ids"; public static final String EXTRA_KEY_IDS = "key_ids"; - // optional parameter: + // optional extras: public static final String EXTRA_PASSPHRASE = "passphrase"; - /* Service Bundle returns */ - public static final String RESULT_CODE = "result_code"; - public static final String RESULT_SIGNATURE = "signature"; - public static final String RESULT_ERRORS = "error"; - public static final String RESULT_INTENT = "intent"; + // GET_KEY + public static final String EXTRA_KEY_ID = "key_id"; - // get actual error object from RESULT_ERRORS + /* Service Intent returns */ + public static final String RESULT_CODE = "result_code"; + + // get actual error object from RESULT_ERROR public static final int RESULT_CODE_ERROR = 0; // success! public static final int RESULT_CODE_SUCCESS = 1; - // executeServiceMethod intent and do it again with intent + // get PendingIntent from RESULT_INTENT, start PendingIntent with startIntentSenderForResult, + // and execute service method again in onActivityResult public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2; + public static final String RESULT_ERROR = "error"; + public static final String RESULT_INTENT = "intent"; + + // DECRYPT_VERIFY + public static final String RESULT_SIGNATURE = "signature"; IOpenPgpService mService; Context mContext; @@ -166,6 +193,7 @@ public class OpenPgpApi { } + @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void executeApiAsync(Intent data, InputStream is, OutputStream os, IOpenPgpCallback callback) { OpenPgpAsyncTask task = new OpenPgpAsyncTask(data, is, os, callback); @@ -188,13 +216,13 @@ public class OpenPgpApi { result = mService.execute(data, null, null); return result; } else { - // send the input and output pfds + // pipe the input and output ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is, new ParcelFileDescriptorUtil.IThreadListener() { @Override public void onThreadFinished(Thread thread) { - Log.d(OpenPgpApi.TAG, "Copy to service finished"); + //Log.d(OpenPgpApi.TAG, "Copy to service finished"); } }); ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os, @@ -202,7 +230,7 @@ public class OpenPgpApi { @Override public void onThreadFinished(Thread thread) { - Log.d(OpenPgpApi.TAG, "Service finished writing!"); + //Log.d(OpenPgpApi.TAG, "Service finished writing!"); } }); @@ -222,7 +250,7 @@ public class OpenPgpApi { Log.e(OpenPgpApi.TAG, "Exception", e); Intent result = new Intent(); result.putExtra(RESULT_CODE, RESULT_CODE_ERROR); - result.putExtra(RESULT_ERRORS, + result.putExtra(RESULT_ERROR, new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage())); return result; } diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java similarity index 99% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java index ecc2b8ec1..cf5864620 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java +++ b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java @@ -31,7 +31,7 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.TextView; -import org.sufficientlysecure.keychain.api.R; +import org.openintents.openpgp.R; import java.util.ArrayList; import java.util.List; diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java b/OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java similarity index 100% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java rename to OpenPGP-Keychain-API/libraries/openpgp-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java diff --git a/OpenPGP-Keychain-API/settings.gradle b/OpenPGP-Keychain-API/settings.gradle index 4df1d7b4f..a819a021b 100644 --- a/OpenPGP-Keychain-API/settings.gradle +++ b/OpenPGP-Keychain-API/settings.gradle @@ -1,2 +1,3 @@ include ':example-app' -include ':libraries:keychain-api-library' \ No newline at end of file +include ':libraries:openpgp-api-library' +include ':libraries:openkeychain-api-library' \ No newline at end of file diff --git a/OpenPGP-Keychain/build.gradle b/OpenPGP-Keychain/build.gradle index 1e48d8bcd..6338774eb 100644 --- a/OpenPGP-Keychain/build.gradle +++ b/OpenPGP-Keychain/build.gradle @@ -3,7 +3,8 @@ apply plugin: 'android' dependencies { compile 'com.android.support:support-v4:19.0.1' compile 'com.android.support:appcompat-v7:19.0.1' - compile project(':OpenPGP-Keychain-API:libraries:keychain-api-library') + compile project(':OpenPGP-Keychain-API:libraries:openpgp-api-library') + compile project(':OpenPGP-Keychain-API:libraries:openkeychain-api-library') compile project(':libraries:HtmlTextView') compile project(':libraries:StickyListHeaders:library') compile project(':libraries:AndroidBootstrap') @@ -18,7 +19,7 @@ dependencies { android { compileSdkVersion 19 - buildToolsVersion "19.0.1" + buildToolsVersion "19.0.3" defaultConfig { minSdkVersion 9 diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml index 250d3edbe..bd45def24 100644 --- a/OpenPGP-Keychain/src/main/AndroidManifest.xml +++ b/OpenPGP-Keychain/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="23104" + android:versionName="2.3.1 beta4"> - - - - - - - - - - - - - - - - - - + android:label="@string/title_preferences" > + + + + + + + + + --> - - - - @@ -452,4 +441,4 @@ - \ No newline at end of file + diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index c1809e4e1..34a3de8d5 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -43,6 +43,8 @@ public final class Constants { public static final class path { public static final String APP_DIR = Environment.getExternalStorageDirectory() + "/OpenPGP-Keychain"; + public static final String APP_DIR_FILE_SEC = APP_DIR + "/secexport.asc"; + public static final String APP_DIR_FILE_PUB = APP_DIR + "/pubexport.asc"; } public static final class pref { @@ -51,7 +53,7 @@ public final class Constants { 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"; + public static final String PASS_PHRASE_CACHE_TTL = "passphraseCacheTtl"; public static final String LANGUAGE = "language"; public static final String FORCE_V3_SIGNATURES = "forceV3Signatures"; public static final String KEY_SERVERS = "keyServers"; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java index a1571e491..1d79edd43 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java @@ -30,7 +30,7 @@ public final class Id { public static final class menu { public static final class option { - public static final int new_pass_phrase = 0x21070001; + public static final int new_passphrase = 0x21070001; public static final int create = 0x21070002; public static final int about = 0x21070003; public static final int manage_public_keys = 0x21070004; @@ -85,12 +85,12 @@ public final class Id { } public static final class dialog { - public static final int pass_phrase = 0x21070001; + public static final int passphrase = 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 new_passphrase = 0x21070004; + public static final int passphrases_do_not_match = 0x21070005; + public static final int no_passphrase = 0x21070006; public static final int saving = 0x21070007; public static final int delete_key = 0x21070008; public static final int import_keys = 0x21070009; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java index 032af4c71..3164de7d1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java @@ -59,7 +59,6 @@ public class ClipboardReflection { * Wrapper around ClipboardManager based on Android version using Reflection API * * @param context - * @param text */ public static CharSequence getClipboardText(Context context) { Object clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java index b55075e6c..24e8ff4c7 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java @@ -56,28 +56,33 @@ public class ActionBarHelper { * Sets custom view on ActionBar for Done/Cancel activities * * @param actionBar - * @param doneText - * @param doneOnClickListener - * @param cancelText - * @param cancelOnClickListener + * @param firstText + * @param firstDrawableId + * @param firstOnClickListener + * @param secondText + * @param secondDrawableId + * @param secondOnClickListener */ - public static void setDoneCancelView(ActionBar actionBar, int doneText, - OnClickListener doneOnClickListener, int cancelText, - OnClickListener cancelOnClickListener) { + public static void setTwoButtonView(ActionBar actionBar, int firstText, int firstDrawableId, + OnClickListener firstOnClickListener, int secondText, int secondDrawableId, + OnClickListener secondOnClickListener) { - // Inflate a "Done"/"Cancel" custom action bar view + // Inflate the custom action bar view final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); final View customActionBarView = inflater.inflate( R.layout.actionbar_custom_view_done_cancel, null); - ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)).setText(doneText); + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); + firstTextView.setText(firstText); + firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - doneOnClickListener); - ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)) - .setText(cancelText); + firstOnClickListener); + TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); + secondTextView.setText(secondText); + secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( - cancelOnClickListener); + secondOnClickListener); // Show the custom action bar view and hide the normal Home icon and title. actionBar.setDisplayShowTitleEnabled(false); @@ -91,20 +96,22 @@ public class ActionBarHelper { * Sets custom view on ActionBar for Done activities * * @param actionBar - * @param doneText - * @param doneOnClickListener + * @param firstText + * @param firstOnClickListener */ - public static void setDoneView(ActionBar actionBar, int doneText, - OnClickListener doneOnClickListener) { + public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId, + OnClickListener firstOnClickListener) { // Inflate a "Done" custom action bar view to serve as the "Up" affordance. final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); final View customActionBarView = inflater .inflate(R.layout.actionbar_custom_view_done, null); - ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)).setText(doneText); + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); + firstTextView.setText(firstText); + firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - doneOnClickListener); + firstOnClickListener); // Show the custom action bar view and hide the normal Home icon and title. actionBar.setDisplayShowTitleEnabled(false); @@ -112,5 +119,4 @@ public class ActionBarHelper { actionBar.setDisplayShowCustomEnabled(true); actionBar.setCustomView(customActionBarView); } - } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java new file mode 100644 index 000000000..f8ed21816 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sufficientlysecure.keychain.helper; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.util.Patterns; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class ContactHelper { + + public static final List getMailAccounts(Context context) { + final Account[] accounts = AccountManager.get(context).getAccounts(); + final Set emailSet = new HashSet(); + for (Account account : accounts) { + if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) { + emailSet.add(account.name); + } + } + return new ArrayList(emailSet); + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java index 21676a2a7..19dfccbde 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java @@ -20,7 +20,6 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; @@ -63,7 +62,7 @@ public class ExportHelper { /** * Show dialog where to export keys */ - public void showExportKeysDialog(final Uri dataUri, final int keyType, + public void showExportKeysDialog(final long[] rowIds, final int keyType, final String exportFilename) { mExportFilename = exportFilename; @@ -75,7 +74,7 @@ public class ExportHelper { Bundle data = message.getData(); mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); - exportKeys(dataUri, keyType); + exportKeys(rowIds, keyType); } } }; @@ -86,7 +85,7 @@ public class ExportHelper { DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { public void run() { String title = null; - if (dataUri == null) { + if (rowIds == null) { // export all keys title = activity.getString(R.string.title_export_keys); } else { @@ -112,7 +111,7 @@ public class ExportHelper { /** * Export keys */ - public void exportKeys(Uri dataUri, int keyType) { + public void exportKeys(long[] rowIds, int keyType) { Log.d(Constants.TAG, "exportKeys started"); // Send all information needed to service to export key in other thread @@ -126,20 +125,17 @@ public class ExportHelper { data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType); - if (dataUri == null) { + if (rowIds == null) { data.putBoolean(KeychainIntentService.EXPORT_ALL, true); } else { - // TODO: put data uri into service??? - long keyRingMasterKeyId = ProviderHelper.getMasterKeyId(activity, dataUri); - - data.putLong(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, keyRingMasterKeyId); + data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_ROW_ID, rowIds); } intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after exporting is done in ApgService KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(activity, - R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) { + activity.getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); @@ -160,7 +156,7 @@ public class ExportHelper { Toast.makeText(activity, toastMessage, Toast.LENGTH_SHORT).show(); } - }; + } }; // Create a new Messenger for the communication back diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java index 639ab17b8..34d90a17f 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java @@ -17,8 +17,6 @@ package org.sufficientlysecure.keychain.helper; -import java.util.Calendar; -import java.util.GregorianCalendar; import java.util.Iterator; import java.util.Set; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java index 493f25707..f18a290b3 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java @@ -144,8 +144,8 @@ public class Preferences { Constants.defaults.KEY_SERVERS); Vector servers = new Vector(); String chunks[] = rawData.split(","); - for (int i = 0; i < chunks.length; ++i) { - String tmp = chunks[i].trim(); + for (String c : chunks) { + String tmp = c.trim(); if (tmp.length() > 0) { servers.add(tmp); } @@ -156,8 +156,8 @@ public class Preferences { public void setKeyServers(String[] value) { SharedPreferences.Editor editor = mSharedPreferences.edit(); String rawData = ""; - for (int i = 0; i < value.length; ++i) { - String tmp = value[i].trim(); + for (String v : value) { + String tmp = v.trim(); if (tmp.length() == 0) { continue; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java index ca97cbd9f..b268de3a6 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java @@ -78,7 +78,7 @@ public class PgpConversionHelper { * * Singles keys are encoded as keyRings with one single key in it by Bouncy Castle * - * @param keysBytes + * @param keyBytes * @return */ public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) { @@ -149,7 +149,7 @@ public class PgpConversionHelper { /** * Convert from PGPSecretKey to byte[] * - * @param keysBytes + * @param key * @return */ public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) { @@ -165,7 +165,7 @@ public class PgpConversionHelper { /** * Convert from PGPSecretKeyRing to byte[] * - * @param keysBytes + * @param keyRing * @return */ public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index fb97f3a5c..252be1036 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -18,8 +18,8 @@ package org.sufficientlysecure.keychain.pgp; import android.content.Context; -import android.os.Bundle; +import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.openpgp.PGPCompressedData; @@ -36,6 +36,7 @@ import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; @@ -53,7 +54,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; @@ -75,9 +76,10 @@ public class PgpDecryptVerify { private InputData data; private OutputStream outStream; - private ProgressDialogUpdater progress; - boolean assumeSymmetric; - String passphrase; + private ProgressDialogUpdater progressDialogUpdater; + private boolean assumeSymmetric; + private String passphrase; + private long enforcedKeyId; private PgpDecryptVerify(Builder builder) { // private Constructor can only be called from Builder @@ -85,9 +87,10 @@ public class PgpDecryptVerify { this.data = builder.data; this.outStream = builder.outStream; - this.progress = builder.progress; + this.progressDialogUpdater = builder.progressDialogUpdater; this.assumeSymmetric = builder.assumeSymmetric; this.passphrase = builder.passphrase; + this.enforcedKeyId = builder.enforcedKeyId; } public static class Builder { @@ -97,9 +100,10 @@ public class PgpDecryptVerify { private OutputStream outStream; // optional - private ProgressDialogUpdater progress = null; + private ProgressDialogUpdater progressDialogUpdater = null; private boolean assumeSymmetric = false; private String passphrase = ""; + private long enforcedKeyId = 0; public Builder(Context context, InputData data, OutputStream outStream) { this.context = context; @@ -107,8 +111,8 @@ public class PgpDecryptVerify { this.outStream = outStream; } - public Builder progress(ProgressDialogUpdater progress) { - this.progress = progress; + public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) { + this.progressDialogUpdater = progressDialogUpdater; return this; } @@ -122,20 +126,32 @@ public class PgpDecryptVerify { return this; } + /** + * Allow this key id alone for decryption. + * This means only ciphertexts encrypted for this private key can be decrypted. + * + * @param enforcedKeyId + * @return + */ + public Builder enforcedKeyId(long enforcedKeyId) { + this.enforcedKeyId = enforcedKeyId; + return this; + } + public PgpDecryptVerify build() { return new PgpDecryptVerify(this); } } public void updateProgress(int message, int current, int total) { - if (progress != null) { - progress.setProgress(message, current, total); + if (progressDialogUpdater != null) { + progressDialogUpdater.setProgress(message, current, total); } } public void updateProgress(int current, int total) { - if (progress != null) { - progress.setProgress(current, total); + if (progressDialogUpdater != null) { + progressDialogUpdater.setProgress(current, total); } } @@ -177,9 +193,8 @@ public class PgpDecryptVerify { * @throws PGPException * @throws SignatureException */ - public Bundle execute() + public PgpDecryptVerifyResult execute() throws IOException, PgpGeneralException, PGPException, SignatureException { - // automatically works with ascii armor input and binary InputStream in = PGPUtil.getDecoderStream(data.getInputStream()); if (in instanceof ArmoredInputStream) { @@ -207,9 +222,9 @@ public class PgpDecryptVerify { * @throws PGPException * @throws SignatureException */ - private Bundle decryptVerify(InputStream in) + private PgpDecryptVerifyResult decryptVerify(InputStream in) throws IOException, PgpGeneralException, PGPException, SignatureException { - Bundle returnData = new Bundle(); + PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); PGPObjectFactory pgpF = new PGPObjectFactory(in); PGPEncryptedDataList enc; @@ -277,9 +292,40 @@ public class PgpDecryptVerify { PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj; secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID()); if (secretKey != null) { + // secret key exists in database + + // allow only a specific key for decryption? + if (enforcedKeyId != 0) { + // TODO: improve this code! get master key directly! + PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, encData.getKeyID()); + long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID(); + Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID()); + Log.d(Constants.TAG, "enforcedKeyId: " + enforcedKeyId); + Log.d(Constants.TAG, "masterKeyId: " + masterKeyId); + + if (enforcedKeyId != masterKeyId) { + throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found)); + } + } + pbe = encData; + + // if no passphrase was explicitly set try to get it from the cache service + if (passphrase == null) { + // returns "" if key has no passphrase + passphrase = PassphraseCacheService.getCachedPassphrase(context, encData.getKeyID()); + + // if passphrase was not cached, return here indicating that a passphrase is missing! + if (passphrase == null) { + returnData.setKeyPassphraseNeeded(true); + return returnData; + } + } + break; } + + } } @@ -289,7 +335,7 @@ public class PgpDecryptVerify { currentProgress += 5; updateProgress(R.string.progress_extracting_key, currentProgress, 100); - PGPPrivateKey privateKey = null; + PGPPrivateKey privateKey; try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( @@ -317,6 +363,7 @@ public class PgpDecryptVerify { PGPObjectFactory plainFact = new PGPObjectFactory(clear); Object dataChunk = plainFact.nextObject(); PGPOnePassSignature signature = null; + OpenPgpSignatureResult signatureResult = null; PGPPublicKey signatureKey = null; int signatureIndex = -1; @@ -334,7 +381,7 @@ public class PgpDecryptVerify { if (dataChunk instanceof PGPOnePassSignatureList) { updateProgress(R.string.progress_processing_signature, currentProgress, 100); - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true); + signatureResult = new OpenPgpSignatureResult(); PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; for (int i = 0; i < sigList.size(); ++i) { signature = sigList.get(i); @@ -354,12 +401,12 @@ public class PgpDecryptVerify { if (signKeyRing != null) { userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); } - returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId); + signatureResult.setUserId(userId); break; } } - returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId); + signatureResult.setKeyId(signatureKeyId); if (signature != null) { JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() @@ -367,7 +414,7 @@ public class PgpDecryptVerify { signature.init(contentVerifierBuilderProvider, signatureKey); } else { - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true); + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); } dataChunk = plainFact.nextObject(); @@ -405,8 +452,7 @@ public class PgpDecryptVerify { try { signature.update(buffer, 0, n); } catch (SignatureException e) { - returnData - .putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false); + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); signature = null; } } @@ -430,17 +476,20 @@ public class PgpDecryptVerify { PGPSignature messageSignature = signatureList.get(signatureIndex); // these are not cleartext signatures! - returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false); + // TODO: what about binary signatures? + signatureResult.setSignatureOnly(false); //Now check binding signatures - boolean keyBinding_isok = verifyKeyBinding(context, messageSignature, signatureKey); - boolean sig_isok = signature.verify(messageSignature); + boolean validKeyBinding = verifyKeyBinding(context, messageSignature, signatureKey); + boolean validSignature = signature.verify(messageSignature); - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, keyBinding_isok & sig_isok); + // TODO: implement CERTIFIED! + if (validKeyBinding & validSignature) { + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); + } } } - // TODO: test if this integrity really check works! if (encryptedData.isIntegrityProtected()) { updateProgress(R.string.progress_verifying_integrity, 95, 100); @@ -455,9 +504,12 @@ public class PgpDecryptVerify { } else { // no integrity check Log.e(Constants.TAG, "Encrypted data was not integrity protected!"); + // TODO: inform user? } updateProgress(R.string.progress_done, 100, 100); + + returnData.setSignatureResult(signatureResult); return returnData; } @@ -474,11 +526,12 @@ public class PgpDecryptVerify { * @throws PGPException * @throws SignatureException */ - private Bundle verifyCleartextSignature(ArmoredInputStream aIn) + private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn) throws IOException, PgpGeneralException, PGPException, SignatureException { - Bundle returnData = new Bundle(); + PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); + OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult(); // cleartext signatures are never encrypted ;) - returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, true); + signatureResult.setSignatureOnly(true); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -504,8 +557,6 @@ public class PgpDecryptVerify { byte[] clearText = out.toByteArray(); outStream.write(clearText); - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true); - updateProgress(R.string.progress_processing_signature, 60, 100); PGPObjectFactory pgpFact = new PGPObjectFactory(aIn); @@ -533,15 +584,17 @@ public class PgpDecryptVerify { if (signKeyRing != null) { userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); } - returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId); + signatureResult.setUserId(userId); break; } } - returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId); + signatureResult.setKeyId(signatureKeyId); if (signature == null) { - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true); + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); + returnData.setSignatureResult(signatureResult); + updateProgress(R.string.progress_done, 100, 100); return returnData; } @@ -569,12 +622,17 @@ public class PgpDecryptVerify { } while (lookAhead != -1); } - boolean sig_isok = signature.verify(); - //Now check binding signatures - boolean keyBinding_isok = verifyKeyBinding(context, signature, signatureKey); + boolean validKeyBinding = verifyKeyBinding(context, signature, signatureKey); + boolean validSignature = signature.verify(); - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, sig_isok & keyBinding_isok); + if (validSignature & validKeyBinding) { + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); + } + + // TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR???? + + returnData.setSignatureResult(signatureResult); updateProgress(R.string.progress_done, 100, 100); return returnData; @@ -582,34 +640,34 @@ public class PgpDecryptVerify { private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) { long signatureKeyId = signature.getKeyID(); - boolean keyBinding_isok = false; - String userId = null; + boolean validKeyBinding = false; + PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context, signatureKeyId); PGPPublicKey mKey = null; if (signKeyRing != null) { mKey = PgpKeyHelper.getMasterKey(signKeyRing); } + if (signature.getKeyID() != mKey.getKeyID()) { - keyBinding_isok = verifyKeyBinding(mKey, signatureKey); + validKeyBinding = verifyKeyBinding(mKey, signatureKey); } else { //if the key used to make the signature was the master key, no need to check binding sigs - keyBinding_isok = true; + validKeyBinding = true; } - return keyBinding_isok; + return validKeyBinding; } private static boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { - boolean subkeyBinding_isok = false; - boolean tmp_subkeyBinding_isok = false; - boolean primkeyBinding_isok = false; - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + boolean validSubkeyBinding = false; + boolean validTempSubkeyBinding = false; + boolean validPrimaryKeyBinding = false; + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); Iterator itr = signingPublicKey.getSignatures(); - subkeyBinding_isok = false; - tmp_subkeyBinding_isok = false; - primkeyBinding_isok = false; while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? //gpg has an invalid subkey binding error on key import I think, but doesn't shout //about keys without subkey signing. Can't get it to import a slightly broken one @@ -619,32 +677,36 @@ public class PgpDecryptVerify { //check and if ok, check primary key binding. try { sig.init(contentVerifierBuilderProvider, masterPublicKey); - tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey); + validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey); } catch (PGPException e) { continue; } catch (SignatureException e) { continue; } - if (tmp_subkeyBinding_isok) - subkeyBinding_isok = true; - if (tmp_subkeyBinding_isok) { - primkeyBinding_isok = verifyPrimaryBinding(sig.getUnhashedSubPackets(), masterPublicKey, signingPublicKey); - if (primkeyBinding_isok) + if (validTempSubkeyBinding) + validSubkeyBinding = true; + if (validTempSubkeyBinding) { + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), + masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) break; - primkeyBinding_isok = verifyPrimaryBinding(sig.getHashedSubPackets(), masterPublicKey, signingPublicKey); - if (primkeyBinding_isok) + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), + masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) break; } } } - return (subkeyBinding_isok & primkeyBinding_isok); + return (validSubkeyBinding & validPrimaryKeyBinding); } - private static boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { - boolean primkeyBinding_isok = false; - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector Pkts, + PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { + boolean validPrimaryKeyBinding = false; + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureList eSigList; if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { @@ -660,8 +722,8 @@ public class PgpDecryptVerify { if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { try { emSig.init(contentVerifierBuilderProvider, signingPublicKey); - primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey); - if (primkeyBinding_isok) + validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) break; } catch (PGPException e) { continue; @@ -671,7 +733,8 @@ public class PgpDecryptVerify { } } } - return primkeyBinding_isok; + + return validPrimaryKeyBinding; } /** @@ -680,10 +743,9 @@ public class PgpDecryptVerify { * @param sig * @param line * @throws SignatureException - * @throws IOException */ private static void processLine(PGPSignature sig, byte[] line) - throws SignatureException, IOException { + throws SignatureException { int length = getLengthWithoutWhiteSpace(line); if (length > 0) { sig.update(line, 0, length); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java new file mode 100644 index 000000000..0477c4fdf --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.pgp; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.openintents.openpgp.OpenPgpSignatureResult; + +public class PgpDecryptVerifyResult implements Parcelable { + boolean symmetricPassphraseNeeded; + boolean keyPassphraseNeeded; + OpenPgpSignatureResult signatureResult; + + public boolean isSymmetricPassphraseNeeded() { + return symmetricPassphraseNeeded; + } + + public void setSymmetricPassphraseNeeded(boolean symmetricPassphraseNeeded) { + this.symmetricPassphraseNeeded = symmetricPassphraseNeeded; + } + + public boolean isKeyPassphraseNeeded() { + return keyPassphraseNeeded; + } + + public void setKeyPassphraseNeeded(boolean keyPassphraseNeeded) { + this.keyPassphraseNeeded = keyPassphraseNeeded; + } + + public OpenPgpSignatureResult getSignatureResult() { + return signatureResult; + } + + public void setSignatureResult(OpenPgpSignatureResult signatureResult) { + this.signatureResult = signatureResult; + } + + public PgpDecryptVerifyResult() { + + } + + public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) { + this.symmetricPassphraseNeeded = b.symmetricPassphraseNeeded; + this.keyPassphraseNeeded = b.keyPassphraseNeeded; + this.signatureResult = b.signatureResult; + } + + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeByte((byte) (symmetricPassphraseNeeded ? 1 : 0)); + dest.writeByte((byte) (keyPassphraseNeeded ? 1 : 0)); + dest.writeParcelable(signatureResult, 0); + } + + public static final Creator CREATOR = new Creator() { + public PgpDecryptVerifyResult createFromParcel(final Parcel source) { + PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult(); + vr.symmetricPassphraseNeeded = source.readByte() == 1; + vr.keyPassphraseNeeded = source.readByte() == 1; + vr.signatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader()); + return vr; + } + + public PgpDecryptVerifyResult[] newArray(final int size) { + return new PgpDecryptVerifyResult[size]; + } + }; +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java index 7ac904d89..1db4f98b1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java @@ -193,11 +193,10 @@ public class PgpHelper { * @param context * @param progress * @param file - * @throws FileNotFoundException * @throws IOException */ public static void deleteFileSecurely(Context context, ProgressDialogUpdater progress, File file) - throws FileNotFoundException, IOException { + throws IOException { long length = file.length(); SecureRandom random = new SecureRandom(); RandomAccessFile raf = new RandomAccessFile(file, "rws"); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index a7a574ee7..138e54f71 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -17,11 +17,9 @@ package org.sufficientlysecure.keychain.pgp; -import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; @@ -29,12 +27,10 @@ import java.util.List; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; @@ -44,11 +40,9 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.HkpKeyServer; -import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.PositionAwareInputStream; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import android.content.Context; @@ -85,13 +79,14 @@ public class PgpImportExport { public boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ArmoredOutputStream aos = new ArmoredOutputStream(bos); + ArmoredOutputStream aos = null; try { + aos = new ArmoredOutputStream(bos); aos.write(keyring.getEncoded()); aos.close(); - String armouredKey = bos.toString("UTF-8"); - server.add(armouredKey); + String armoredKey = bos.toString("UTF-8"); + server.add(armoredKey); return true; } catch (IOException e) { @@ -101,7 +96,8 @@ public class PgpImportExport { return false; } finally { try { - bos.close(); + if (aos != null) aos.close(); + if (bos != null) bos.close(); } catch (IOException e) { } } @@ -161,59 +157,53 @@ public class PgpImportExport { return returnData; } - public Bundle exportKeyRings(ArrayList keyRingMasterKeyIds, int keyType, - OutputStream outStream) throws PgpGeneralException, FileNotFoundException, + public Bundle exportKeyRings(ArrayList keyRingRowIds, int keyType, + OutputStream outStream) throws PgpGeneralException, PGPException, IOException { Bundle returnData = new Bundle(); + int rowIdsSize = keyRingRowIds.size(); + updateProgress( mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, - keyRingMasterKeyIds.size()), 0, 100); + rowIdsSize), 0, 100); if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { throw new PgpGeneralException( mContext.getString(R.string.error_external_storage_not_ready)); } + // For each row id + for (int i = 0; i < rowIdsSize; ++i) { + // Create an output stream + ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream); + arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext)); - if (keyType == Id.type.secret_key) { - ArmoredOutputStream outSec = new ArmoredOutputStream(outStream); - outSec.setHeader("Version", PgpHelper.getFullVersion(mContext)); - - for (int i = 0; i < keyRingMasterKeyIds.size(); ++i) { - updateProgress(i * 100 / keyRingMasterKeyIds.size() / 2, 100); - - PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId( - mContext, keyRingMasterKeyIds.get(i)); + // If the keyType is secret get the PGPSecretKeyRing + // based on the row id and encode it to the output + if (keyType == Id.type.secret_key) { + updateProgress(i * 100 / rowIdsSize / 2, 100); + PGPSecretKeyRing secretKeyRing = + ProviderHelper.getPGPSecretKeyRingByRowId(mContext, keyRingRowIds.get(i)); if (secretKeyRing != null) { - secretKeyRing.encode(outSec); + secretKeyRing.encode(arOutStream); } - } - outSec.close(); - } else { - // export public keyrings... - ArmoredOutputStream outPub = new ArmoredOutputStream(outStream); - outPub.setHeader("Version", PgpHelper.getFullVersion(mContext)); - - for (int i = 0; i < keyRingMasterKeyIds.size(); ++i) { - // double the needed time if exporting both public and secret parts - if (keyType == Id.type.secret_key) { - updateProgress(i * 100 / keyRingMasterKeyIds.size() / 2, 100); - } else { - updateProgress(i * 100 / keyRingMasterKeyIds.size(), 100); - } - - PGPPublicKeyRing publicKeyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId( - mContext, keyRingMasterKeyIds.get(i)); + // Else if it's a public key get the PGPPublicKeyRing + // and encode that to the output + } else { + updateProgress(i * 100 / rowIdsSize, 100); + PGPPublicKeyRing publicKeyRing = + ProviderHelper.getPGPPublicKeyRingByRowId(mContext, keyRingRowIds.get(i)); if (publicKeyRing != null) { - publicKeyRing.encode(outPub); + publicKeyRing.encode(arOutStream); } } - outPub.close(); + + arOutStream.close(); } - returnData.putInt(KeychainIntentService.RESULT_EXPORT, keyRingMasterKeyIds.size()); + returnData.putInt(KeychainIntentService.RESULT_EXPORT, rowIdsSize); updateProgress(R.string.progress_done, 100, 100); @@ -234,7 +224,7 @@ public class PgpImportExport { for (PGPSecretKey testSecretKey : new IterableIterator( secretKeyRing.getSecretKeys())) { if (!testSecretKey.isMasterKey()) { - if (PgpKeyHelper.isSecretKeyPrivateEmpty(testSecretKey)) { + if (testSecretKey.isPrivateKeyEmpty()) { // this is bad, something is very wrong... save = false; status = Id.return_value.bad; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index 38480a766..902dd8da9 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -32,6 +32,7 @@ import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -415,28 +416,27 @@ public class PgpKeyHelper { String algorithmStr = null; switch (algorithm) { - case PGPPublicKey.RSA_ENCRYPT: - case PGPPublicKey.RSA_GENERAL: - case PGPPublicKey.RSA_SIGN: { - algorithmStr = "RSA"; - break; - } + case PGPPublicKey.RSA_ENCRYPT: + case PGPPublicKey.RSA_GENERAL: + case PGPPublicKey.RSA_SIGN: { + algorithmStr = "RSA"; + break; + } + case PGPPublicKey.DSA: { + algorithmStr = "DSA"; + break; + } - case PGPPublicKey.DSA: { - algorithmStr = "DSA"; - break; - } + case PGPPublicKey.ELGAMAL_ENCRYPT: + case PGPPublicKey.ELGAMAL_GENERAL: { + algorithmStr = "ElGamal"; + break; + } - case PGPPublicKey.ELGAMAL_ENCRYPT: - case PGPPublicKey.ELGAMAL_GENERAL: { - algorithmStr = "ElGamal"; - break; - } - - default: { - algorithmStr = "Unknown"; - break; - } + default: { + algorithmStr = "Unknown"; + break; + } } if(keySize > 0) return algorithmStr + ", " + keySize + " bit"; @@ -444,31 +444,6 @@ public class PgpKeyHelper { return algorithmStr; } - /** - * Converts fingerprint to hex with whitespaces after 4 characters - * - * @param fp - * @return - */ - public static String convertFingerprintToHex(byte[] fp, boolean chunked) { - String fingerPrint = ""; - for (int i = 0; i < fp.length; ++i) { - if (chunked && i != 0 && i % 10 == 0) { - fingerPrint += " "; - } else if (chunked && i != 0 && i % 2 == 0) { - fingerPrint += " "; - } - String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase(Locale.US); - while (chunk.length() < 2) { - chunk = "0" + chunk; - } - fingerPrint += chunk; - } - - return fingerPrint; - - } - public static String getFingerPrint(Context context, long keyId) { PGPPublicKey key = ProviderHelper.getPGPPublicKeyByKeyId(context, keyId); // if it is no public key get it from your own keys... @@ -484,52 +459,68 @@ public class PgpKeyHelper { return convertFingerprintToHex(key.getFingerprint(), true); } - public static boolean isSecretKeyPrivateEmpty(PGPSecretKey secretKey) { - return secretKey.isPrivateKeyEmpty(); - } - -// public static boolean isSecretKeyPrivateEmpty(Context context, long keyId) { -// PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId); -// if (secretKey == null) { -// Log.e(Constants.TAG, "Key could not be found!"); -// return false; // could be a public key, assume it is not empty -// } -// return isSecretKeyPrivateEmpty(secretKey); -// } - - public static String convertKeyIdToHex(long keyId) { - String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US); - while (fingerPrint.length() < 8) { - fingerPrint = "0" + fingerPrint; + /** + * Converts fingerprint to hex (optional: with whitespaces after 4 characters) + *

+ * Fingerprint is shown using lowercase characters. Studies have shown that humans can + * better differentiate between numbers and letters when letters are lowercase. + * + * @param fingerprint + * @param split split into 4 character chunks + * @return + */ + public static String convertFingerprintToHex(byte[] fingerprint, boolean split) { + String hexString = Hex.toHexString(fingerprint); + if (split) { + hexString = hexString.replaceAll("(.{4})(?!$)", "$1 "); } - return fingerPrint; + + return hexString; } /** - * TODO: documentation - * + * Convert key id from long to 64 bit hex string + *

+ * V4: "The Key ID is the low-order 64 bits of the fingerprint" + *

+ * see http://tools.ietf.org/html/rfc4880#section-12.2 + * * @param keyId * @return */ - public static String convertKeyToHex(long keyId) { - return convertKeyIdToHex(keyId >> 32) + convertKeyIdToHex(keyId); + public static String convertKeyIdToHex(long keyId) { + return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId); } - public static long convertHexToKeyId(String data) { - int len = data.length(); - String s2 = data.substring(len - 8); - String s1 = data.substring(0, len - 8); + private static String convertKeyIdToHex32bit(long keyId) { + String hexString = Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.US); + while (hexString.length() < 8) { + hexString = "0" + hexString; + } + return hexString; + } + + /** + * Used in HkpKeyServer to convert hex encoded key ids back to long. + * + * @param hexString + * @return + */ + public static long convertHexToKeyId(String hexString) { + int len = hexString.length(); + String s2 = hexString.substring(len - 8); + String s1 = hexString.substring(0, len - 8); return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16); } /** * Splits userId string into naming part, email part, and comment part - * + * * @param userId * @return array with naming (0), email (1), comment (2) */ public static String[] splitUserId(String userId) { - String[] result = new String[] { null, null, null }; + String[] result = new String[]{null, null, null}; if (userId == null || userId.equals("")) { return result; @@ -550,7 +541,6 @@ public class PgpKeyHelper { result[0] = matcher.group(1); result[1] = matcher.group(3); result[2] = matcher.group(2); - return result; } return result; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 7caee4048..5ebb53f20 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -107,7 +107,7 @@ public class PgpKeyOperation { * * @param algorithmChoice * @param keySize - * @param passPhrase + * @param passphrase * @param isMasterKey * @return * @throws NoSuchAlgorithmException @@ -118,7 +118,7 @@ public class PgpKeyOperation { */ // TODO: key flags? - public PGPSecretKey createKey(int algorithmChoice, int keySize, String passPhrase, + public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase, boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, PgpGeneralException, InvalidAlgorithmParameterException { @@ -126,8 +126,8 @@ public class PgpKeyOperation { throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit)); } - if (passPhrase == null) { - passPhrase = ""; + if (passphrase == null) { + passphrase = ""; } int algorithm = 0; @@ -181,7 +181,7 @@ public class PgpKeyOperation { // Build key encrypter and decrypter based on passphrase PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( PGPEncryptedData.CAST5, sha1Calc) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passPhrase.toCharArray()); + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); PGPSecretKey secKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), sha1Calc, isMasterKey, keyEncryptor); @@ -190,7 +190,7 @@ public class PgpKeyOperation { } public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase, - String newPassPhrase) throws IOException, PGPException, PGPException, + String newPassPhrase) throws IOException, PGPException, NoSuchProviderException { updateProgress(R.string.progress_building_key, 0, 100); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 171aa9912..f072e13be 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -342,7 +342,7 @@ public class KeychainProvider extends ContentProvider { /** * Returns type of the query (secret/public) * - * @param uri + * @param match * @return */ private int getKeyType(int match) { @@ -1039,7 +1039,8 @@ public class KeychainProvider extends ContentProvider { * Build default selection statement for KeyRings. If no extra selection is specified only build * where clause with rowId * - * @param uri + * @param defaultSelection + * @param keyType * @param selection * @return */ diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index c1b2ef6e3..f740e1c7c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -100,7 +100,7 @@ public class ProviderHelper { } /** - * Retrieves the actual PGPPublicKeyRing object from the database blob based on the maserKeyId + * Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId */ public static PGPPublicKeyRing getPGPPublicKeyRingByMasterKeyId(Context context, long masterKeyId) { @@ -123,11 +123,8 @@ public class ProviderHelper { */ public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) { PGPPublicKeyRing keyRing = getPGPPublicKeyRingByKeyId(context, keyId); - if (keyRing == null) { - return null; - } - return keyRing.getPublicKey(keyId); + return (keyRing == null)? null : keyRing.getPublicKey(keyId); } /** @@ -162,11 +159,8 @@ public class ProviderHelper { */ public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) { PGPSecretKeyRing keyRing = getPGPSecretKeyRingByKeyId(context, keyId); - if (keyRing == null) { - return null; - } - return keyRing.getSecretKey(keyId); + return (keyRing == null) ? null : keyRing.getSecretKey(keyId); } /** @@ -411,10 +405,10 @@ public class ProviderHelper { long keyRingRowId, PGPSecretKey key, int rank) throws IOException { ContentValues values = new ContentValues(); - boolean has_private = true; + boolean hasPrivate = true; if (key.isMasterKey()) { - if (PgpKeyHelper.isSecretKeyPrivateEmpty(key)) { - has_private = false; + if (key.isPrivateKeyEmpty()) { + hasPrivate = false; } } @@ -422,8 +416,8 @@ public class ProviderHelper { values.put(Keys.IS_MASTER_KEY, key.isMasterKey()); values.put(Keys.ALGORITHM, key.getPublicKey().getAlgorithm()); values.put(Keys.KEY_SIZE, key.getPublicKey().getBitStrength()); - values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key) && has_private)); - values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key) && has_private)); + values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key) && hasPrivate)); + values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key) && hasPrivate)); values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key)); values.put(Keys.IS_REVOKED, key.getPublicKey().isRevoked()); values.put(Keys.CREATION, PgpKeyHelper.getCreationDate(key).getTime() / 1000); @@ -480,6 +474,30 @@ public class ProviderHelper { return masterKeyIds; } + /** + * Private helper method + */ + private static ArrayList getKeyRingsRowIds(Context context, Uri queryUri) { + Cursor cursor = context.getContentResolver().query(queryUri, + new String[]{KeyRings._ID}, null, null, null); + + ArrayList rowIds = new ArrayList(); + if (cursor != null) { + int IdCol = cursor.getColumnIndex(KeyRings._ID); + if (cursor.moveToFirst()) { + do { + rowIds.add(cursor.getLong(IdCol)); + } while (cursor.moveToNext()); + } + } + + if (cursor != null) { + cursor.close(); + } + + return rowIds; + } + /** * Retrieves ids of all SecretKeyRings */ @@ -496,6 +514,22 @@ public class ProviderHelper { return getKeyRingsMasterKeyIds(context, queryUri); } + /** + * Retrieves ids of all SecretKeyRings + */ + public static ArrayList getSecretKeyRingsRowIds(Context context) { + Uri queryUri = KeyRings.buildSecretKeyRingsUri(); + return getKeyRingsRowIds(context, queryUri); + } + + /** + * Retrieves ids of all PublicKeyRings + */ + public static ArrayList getPublicKeyRingsRowIds(Context context) { + Uri queryUri = KeyRings.buildPublicKeyRingsUri(); + return getKeyRingsRowIds(context, queryUri); + } + public static void deletePublicKeyRing(Context context, long rowId) { ContentResolver cr = context.getContentResolver(); cr.delete(KeyRings.buildPublicKeyRingsUri(Long.toString(rowId)), null, null); @@ -722,7 +756,7 @@ public class ProviderHelper { String armoredKey = bos.toString("UTF-8"); - Log.d(Constants.TAG, "armouredKey:" + armoredKey); + Log.d(Constants.TAG, "armoredKey:" + armoredKey); output.add(armoredKey); } catch (IOException e) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 302dbea0b..93238349d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -44,11 +44,13 @@ import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpImportExport; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; @@ -152,6 +154,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial public static final String EXPORT_KEY_TYPE = "export_key_type"; public static final String EXPORT_ALL = "export_all"; public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id"; + public static final String EXPORT_KEY_RING_ROW_ID = "export_key_rind_row_id"; // upload key public static final String UPLOAD_KEY_SERVER = "upload_key_server"; @@ -181,13 +184,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial // decrypt/verify public static final String RESULT_DECRYPTED_STRING = "decrypted_message"; public static final String RESULT_DECRYPTED_BYTES = "decrypted_data"; - public static final String RESULT_SIGNATURE = "signature"; - public static final String RESULT_SIGNATURE_KEY_ID = "signature_key_id"; - public static final String RESULT_SIGNATURE_USER_ID = "signature_user_id"; - public static final String RESULT_CLEARTEXT_SIGNATURE_ONLY = "signature_only"; - - public static final String RESULT_SIGNATURE_SUCCESS = "signature_success"; - public static final String RESULT_SIGNATURE_UNKNOWN = "signature_unknown"; + public static final String RESULT_DECRYPT_VERIFY_RESULT = "signature"; // import public static final String RESULT_IMPORT_ADDED = "added"; @@ -206,7 +203,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial private boolean mIsCanceled; public KeychainIntentService() { - super("ApgService"); + super("KeychainIntentService"); } @Override @@ -489,15 +486,17 @@ public class KeychainIntentService extends IntentService implements ProgressDial // verifyText and decrypt returning additional resultData values for the // verification of signatures PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream); - builder.progress(this); + builder.progressDialogUpdater(this); builder.assumeSymmetric(assumeSymmetricEncryption) .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); - resultData = builder.build().execute(); + PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); outStream.close(); + resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult); + /* Output */ switch (target) { @@ -599,13 +598,23 @@ public class KeychainIntentService extends IntentService implements ProgressDial String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE); /* Operation */ + int keysTotal = 2; + int keysCreated = 0; + setProgress( + getApplicationContext().getResources().getQuantityString(R.plurals.progress_generating, keysTotal), + keysCreated, + keysTotal); PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); PGPSecretKey masterKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, true); + keysCreated++; + setProgress(keysCreated, keysTotal); PGPSecretKey subKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, false); + keysCreated++; + setProgress(keysCreated, keysTotal); // TODO: default to one master for cert, one sub for encrypt and one sub // for sign @@ -668,10 +677,12 @@ public class KeychainIntentService extends IntentService implements ProgressDial String outputFile = data.getString(EXPORT_FILENAME); + long[] rowIds = new long[0]; + + // If not exporting all keys get the rowIds of the keys to export from the intent boolean exportAll = data.getBoolean(EXPORT_ALL); - long keyRingMasterKeyId = -1; if (!exportAll) { - keyRingMasterKeyId = data.getLong(EXPORT_KEY_RING_MASTER_KEY_ID); + rowIds = data.getLongArray(EXPORT_KEY_RING_ROW_ID); } /* Operation */ @@ -684,24 +695,26 @@ public class KeychainIntentService extends IntentService implements ProgressDial // OutputStream FileOutputStream outStream = new FileOutputStream(outputFile); - ArrayList keyRingMasterKeyIds = new ArrayList(); + ArrayList keyRingRowIds = new ArrayList(); if (exportAll) { - // get all key ring row ids based on export type + // get all key ring row ids based on export type if (keyType == Id.type.public_key) { - keyRingMasterKeyIds = ProviderHelper.getPublicKeyRingsMasterKeyIds(this); + keyRingRowIds = ProviderHelper.getPublicKeyRingsRowIds(this); } else { - keyRingMasterKeyIds = ProviderHelper.getSecretKeyRingsMasterKeyIds(this); + keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this); } } else { - keyRingMasterKeyIds.add(keyRingMasterKeyId); + for(long rowId : rowIds) { + keyRingRowIds.add(rowId); + } } - Bundle resultData = new Bundle(); + Bundle resultData; PgpImportExport pgpImportExport = new PgpImportExport(this, this); resultData = pgpImportExport - .exportKeyRings(keyRingMasterKeyIds, keyType, outStream); + .exportKeyRings(keyRingRowIds, keyType, outStream); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); } catch (Exception e) { @@ -751,7 +764,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial */ // need to have access to the bufferedInput, so we can reuse it for the possible // PGPObject chunks after the first one, e.g. files with several consecutive ASCII - // armour blocks + // armor blocks BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKey)); try { @@ -867,10 +880,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial } /** - * Set progress of ProgressDialog by sending message to handler on UI thread + * Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread */ public void setProgress(String message, int progress, int max) { - Log.d(Constants.TAG, "Send message by setProgress with progress=" + progress + ", max=" + Log.d(Constants.TAG, "Send message by setProgress with progressDialogUpdater=" + progress + ", max=" + max); Bundle data = new Bundle(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index 6eba9cc83..ebc002ceb 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -21,7 +21,6 @@ import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.R; import android.app.Activity; -import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.os.Bundle; import android.os.Handler; @@ -51,21 +50,26 @@ public class KeychainIntentServiceHandler extends Handler { this.mActivity = activity; } - public KeychainIntentServiceHandler(Activity activity, ProgressDialogFragment progressDialogFragment) { + public KeychainIntentServiceHandler(Activity activity, + ProgressDialogFragment progressDialogFragment) { this.mActivity = activity; this.mProgressDialogFragment = progressDialogFragment; } - public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, int progressDialogStyle) { - this(activity, progressDialogMessageId, progressDialogStyle, false, null); + public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, + int progressDialogStyle) { + this(activity, progressDialogMessage, progressDialogStyle, false, null); } - public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, + public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, int progressDialogStyle, boolean cancelable, OnCancelListener onCancelListener) { this.mActivity = activity; - this.mProgressDialogFragment = ProgressDialogFragment.newInstance(progressDialogMessageId, - progressDialogStyle, cancelable, onCancelListener); + this.mProgressDialogFragment = ProgressDialogFragment.newInstance( + progressDialogMessage, + progressDialogStyle, + cancelable, + onCancelListener); } public void showProgressDialog(FragmentActivity activity) { @@ -84,43 +88,43 @@ public class KeychainIntentServiceHandler extends Handler { Bundle data = message.getData(); switch (message.arg1) { - case MESSAGE_OKAY: - mProgressDialogFragment.dismissAllowingStateLoss(); + case MESSAGE_OKAY: + mProgressDialogFragment.dismissAllowingStateLoss(); - break; + break; - case MESSAGE_EXCEPTION: - mProgressDialogFragment.dismissAllowingStateLoss(); + case MESSAGE_EXCEPTION: + mProgressDialogFragment.dismissAllowingStateLoss(); - // show error from service - if (data.containsKey(DATA_ERROR)) { - Toast.makeText(mActivity, - mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)), - Toast.LENGTH_SHORT).show(); - } - - break; - - case MESSAGE_UPDATE_PROGRESS: - if (data.containsKey(DATA_PROGRESS) && data.containsKey(DATA_PROGRESS_MAX)) { - - // update progress from service - if (data.containsKey(DATA_MESSAGE)) { - mProgressDialogFragment.setProgress(data.getString(DATA_MESSAGE), - data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); - } else if (data.containsKey(DATA_MESSAGE_ID)) { - mProgressDialogFragment.setProgress(data.getInt(DATA_MESSAGE_ID), - data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); - } else { - mProgressDialogFragment.setProgress(data.getInt(DATA_PROGRESS), - data.getInt(DATA_PROGRESS_MAX)); + // show error from service + if (data.containsKey(DATA_ERROR)) { + Toast.makeText(mActivity, + mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)), + Toast.LENGTH_SHORT).show(); } - } - break; + break; - default: - break; + case MESSAGE_UPDATE_PROGRESS: + if (data.containsKey(DATA_PROGRESS) && data.containsKey(DATA_PROGRESS_MAX)) { + + // update progress from service + if (data.containsKey(DATA_MESSAGE)) { + mProgressDialogFragment.setProgress(data.getString(DATA_MESSAGE), + data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); + } else if (data.containsKey(DATA_MESSAGE_ID)) { + mProgressDialogFragment.setProgress(data.getInt(DATA_MESSAGE_ID), + data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); + } else { + mProgressDialogFragment.setProgress(data.getInt(DATA_PROGRESS), + data.getInt(DATA_PROGRESS_MAX)); + } + } + + break; + + default: + break; } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index abd2320e3..ce34d451d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -21,6 +21,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import android.util.LongSparseArray; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPSecretKey; @@ -77,7 +78,7 @@ public class PassphraseCacheService extends Service { private BroadcastReceiver mIntentReceiver; - private HashMap mPassphraseCache = new HashMap(); + private LongSparseArray mPassphraseCache = new LongSparseArray(); Context mContext; @@ -347,7 +348,7 @@ public class PassphraseCacheService extends Service { Log.d(TAG, "Timeout of keyId " + keyId + ", removed from memory!"); // stop whole service if no cached passphrases remaining - if (mPassphraseCache.isEmpty()) { + if (mPassphraseCache.size() == 0) { Log.d(TAG, "No passphrases remaining in memory, stopping service!"); stopSelf(); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java index a7afc9698..178b2fc67 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java @@ -41,7 +41,7 @@ public class AppSettingsActivity extends ActionBarActivity { super.onCreate(savedInstanceState); // Inflate a "Done" custom action bar - ActionBarHelper.setDoneView(getSupportActionBar(), R.string.api_settings_save, + ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.api_settings_save, R.drawable.ic_action_done, new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java index 8c8e6f00a..f697faa6e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java @@ -21,7 +21,6 @@ import android.app.PendingIntent; import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -33,9 +32,11 @@ import org.spongycastle.util.Arrays; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -103,9 +104,8 @@ public class OpenPgpService extends RemoteService { // return PendingIntent to be executed by client Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); return result; } @@ -114,8 +114,8 @@ public class OpenPgpService extends RemoteService { } Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIdsArray); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } @@ -130,9 +130,8 @@ public class OpenPgpService extends RemoteService { // return PendingIntent to be executed by client Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); return result; } @@ -179,9 +178,9 @@ public class OpenPgpService extends RemoteService { return result; } catch (Exception e) { Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } } @@ -208,9 +207,9 @@ public class OpenPgpService extends RemoteService { } } else { Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!")); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } @@ -267,9 +266,9 @@ public class OpenPgpService extends RemoteService { return result; } catch (Exception e) { Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } } @@ -284,98 +283,30 @@ public class OpenPgpService extends RemoteService { Intent result = new Intent(); try { - // TODO: - // fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream - // should we allow to decrypt everything under every key id or only the one set? - // TODO: instead of trying to get the passphrase before - // pause stream when passphrase is missing and then resume - - // TODO: put this code into PgpDecryptVerify class - - // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the - // app, Fix this? -// String passphrase = null; -// if (!signedOnly) { -// // BEGIN Get key -// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it -// // better! -// InputStream inputStream2 = new ByteArrayInputStream(inputBytes); -// -// // TODO: duplicates functions from DecryptActivity! -// long secretKeyId; -// try { -// if (inputStream2.markSupported()) { -// // should probably set this to the max size of two -// // pgpF objects, if it even needs to be anything other -// // than 0. -// inputStream2.mark(200); -// } -// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2); -// if (secretKeyId == Id.key.none) { -// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found)); -// } -// } catch (NoAsymmetricEncryptionException e) { -// if (inputStream2.markSupported()) { -// inputStream2.reset(); -// } -// secretKeyId = Id.key.symmetric; -// if (!PgpDecryptVerify.hasSymmetricEncryption(this, inputStream2)) { -// throw new PgpGeneralException( -// getString(R.string.error_no_known_encryption_found)); -// } -// // we do not support symmetric decryption from the API! -// throw new Exception("Symmetric decryption is not supported!"); -// } -// -// Log.d(Constants.TAG, "secretKeyId " + secretKeyId); - - // NOTE: currently this only gets the passphrase for the key set for this client - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); - return passphraseBundle; - } - + String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); long inputLength = is.available(); InputData inputData = new InputData(is, inputLength); - Bundle outputBundle; PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os); - - builder.assumeSymmetric(false) + builder.assumeSymmetric(false) // no support for symmetric encryption + .enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption .passphrase(passphrase); - // TODO: this also decrypts with other secret keys that have no passphrase!!! - outputBundle = builder.build().execute(); + // TODO: currently does not support binary signed-only content + PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); - //TODO: instead of using all these wrapping use OpenPgpSignatureResult directly - // in DecryptVerify class and then in DecryptActivity - boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false); - if (signature) { - long signatureKeyId = outputBundle - .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0); - String signatureUserId = outputBundle - .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); - boolean signatureSuccess = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false); - boolean signatureUnknown = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false); - boolean signatureOnly = outputBundle - .getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false); + if (decryptVerifyResult.isKeyPassphraseNeeded()) { + // get PendingIntent for passphrase input, add it to given params and return to client + Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); + return passphraseBundle; + } else if (decryptVerifyResult.isSymmetricPassphraseNeeded()) { + throw new PgpGeneralException("Decryption of symmetric content not supported by API!"); + } - int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR; - if (signatureSuccess) { - signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED; - } else if (signatureUnknown) { - signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY; - - // If signature is unknown we return an additional PendingIntent + OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); + if (signatureResult != null) { + if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) { + // If signature is unknown we return an _additional_ PendingIntent // to retrieve the missing key // TODO!!! Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); @@ -389,11 +320,9 @@ public class OpenPgpService extends RemoteService { result.putExtra(OpenPgpApi.RESULT_INTENT, pi); } - - OpenPgpSignatureResult sigResult = new OpenPgpSignatureResult(signatureStatus, - signatureUserId, signatureOnly, signatureKeyId); - result.putExtra(OpenPgpApi.RESULT_SIGNATURE, sigResult); + result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); } + } finally { is.close(); os.close(); @@ -403,9 +332,44 @@ public class OpenPgpService extends RemoteService { return result; } catch (Exception e) { Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); + return result; + } + } + + private Intent getKeyImpl(Intent data) { + try { + long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0); + + if (ProviderHelper.getPGPPublicKeyByKeyId(this, keyId) == null) { + Intent result = new Intent(); + + // If keys are not in db we return an additional PendingIntent + // to retrieve the missing key + // TODO!!! + Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); + intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); + intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo"); + intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); + + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), + PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0); + + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); + return result; + } else { + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; + } + } catch (Exception e) { + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_ERROR, + new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } } @@ -431,7 +395,7 @@ public class OpenPgpService extends RemoteService { if (data == null) { Intent result = new Intent(); OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); - result.putExtra(OpenPgpApi.RESULT_ERRORS, error); + result.putExtra(OpenPgpApi.RESULT_ERROR, error); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } @@ -440,7 +404,7 @@ public class OpenPgpService extends RemoteService { if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) { Intent result = new Intent(); OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); - result.putExtra(OpenPgpApi.RESULT_ERRORS, error); + result.putExtra(OpenPgpApi.RESULT_ERROR, error); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } @@ -471,13 +435,12 @@ public class OpenPgpService extends RemoteService { return signImpl(data, input, output, appSettings); } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { return encryptAndSignImpl(data, input, output, appSettings, false); - } else if (OpenPgpApi.ACTION_SIGN_AND_ENCTYPT.equals(action)) { + } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { return encryptAndSignImpl(data, input, output, appSettings, true); } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { return decryptAndVerifyImpl(data, input, output, appSettings); - } else if (OpenPgpApi.ACTION_DOWNLOAD_KEYS.equals(action)) { - // TODO! - return null; + } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) { + return getKeyImpl(data); } else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) { return getKeyIdsImpl(data); } else { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java index e7b3b2945..cb556be39 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java @@ -72,7 +72,7 @@ public abstract class RemoteService extends Service { // return error Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERRORS, + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); return result; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java index 11b3ee217..8fb562884 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java @@ -88,7 +88,7 @@ public class RemoteServiceActivity extends ActionBarActivity { final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow, + ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.api_register_allow, R.drawable.ic_action_done, new View.OnClickListener() { @Override public void onClick(View v) { @@ -108,7 +108,7 @@ public class RemoteServiceActivity extends ActionBarActivity { RemoteServiceActivity.this.finish(); } } - }, R.string.api_register_disallow, new View.OnClickListener() { + }, R.string.api_register_disallow, R.drawable.ic_action_cancel, new View.OnClickListener() { @Override public void onClick(View v) { // Disallow @@ -161,7 +161,7 @@ public class RemoteServiceActivity extends ActionBarActivity { } // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay, + ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, new View.OnClickListener() { @Override public void onClick(View v) { @@ -173,7 +173,7 @@ public class RemoteServiceActivity extends ActionBarActivity { RemoteServiceActivity.this.setResult(RESULT_OK, resultData); RemoteServiceActivity.this.finish(); } - }, R.string.btn_do_not_save, new View.OnClickListener() { + }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { @Override public void onClick(View v) { // cancel @@ -214,7 +214,7 @@ public class RemoteServiceActivity extends ActionBarActivity { String text = "" + errorMessage + ""; // Inflate a "Done" custom action bar view - ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay, + ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, new View.OnClickListener() { @Override diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index aab6b81d9..029dda1a0 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -230,7 +230,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements // Message is received after signing is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - R.string.progress_signing, ProgressDialog.STYLE_SPINNER) { + getString(R.string.progress_signing), ProgressDialog.STYLE_SPINNER) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); @@ -249,7 +249,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements finish(); } } - }; + } }; // Create a new Messenger for the communication back @@ -283,7 +283,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements // Message is received after uploading is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) { + getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); @@ -295,7 +295,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements setResult(RESULT_OK); finish(); } - }; + } }; // Create a new Messenger for the communication back diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 9bb675db0..38d763ce4 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -25,6 +25,7 @@ import java.io.FileNotFoundException; import java.io.InputStream; import java.util.regex.Matcher; +import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; @@ -32,6 +33,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.FileHelper; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; @@ -528,6 +530,10 @@ public class DecryptActivity extends DrawerActivity { Log.e(Constants.TAG, "File not found!", e); AppMsg.makeText(this, getString(R.string.error_file_not_found, e.getMessage()), AppMsg.STYLE_ALERT).show(); + } finally { + try { + if (inStream != null) inStream.close(); + } catch (Exception e){ } } } else { inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes()); @@ -644,7 +650,7 @@ public class DecryptActivity extends DrawerActivity { // Message is received after encrypting is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - R.string.progress_decrypting, ProgressDialog.STYLE_HORIZONTAL) { + getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); @@ -690,11 +696,15 @@ public class DecryptActivity extends DrawerActivity { } - if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE)) { - String userId = returnData - .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); - mSignatureKeyId = returnData - .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); + PgpDecryptVerifyResult decryptVerifyResult = + returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT); + + OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); + + if (signatureResult != null) { + + String userId = signatureResult.getUserId(); + mSignatureKeyId = signatureResult.getKeyId(); mUserIdRest.setText("id: " + PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId)); if (userId == null) { @@ -707,26 +717,37 @@ public class DecryptActivity extends DrawerActivity { } mUserId.setText(userId); - if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS)) { - mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); - mLookupKey.setVisibility(View.GONE); - } else if (returnData - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - mLookupKey.setVisibility(View.VISIBLE); - AppMsg.makeText(DecryptActivity.this, - R.string.unknown_signature, - AppMsg.STYLE_ALERT).show(); - } else { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - mLookupKey.setVisibility(View.GONE); + switch (signatureResult.getStatus()) { + case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: { + mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); + mLookupKey.setVisibility(View.GONE); + break; + } + + // TODO! +// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: { +// break; +// } + + case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: { + mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + mLookupKey.setVisibility(View.VISIBLE); + AppMsg.makeText(DecryptActivity.this, + R.string.unknown_signature, + AppMsg.STYLE_ALERT).show(); + break; + } + + default: { + mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + mLookupKey.setVisibility(View.GONE); + break; + } } mSignatureLayout.setVisibility(View.VISIBLE); } } } - - ; }; // Create a new Messenger for the communication back diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index e2822c898..0c35bb2b1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -92,12 +92,12 @@ public class EditKeyActivity extends ActionBarActivity { private SectionView mUserIdsView; private SectionView mKeysView; - private String mCurrentPassPhrase = null; + private String mCurrentPassphrase = null; private String mNewPassPhrase = null; private String mSavedNewPassPhrase = null; private boolean mIsPassPhraseSet; - private BootstrapButton mChangePassPhrase; + private BootstrapButton mChangePassphrase; private CheckBox mNoPassphrase; @@ -134,14 +134,14 @@ public class EditKeyActivity extends ActionBarActivity { * @param intent */ private void handleActionCreateKey(Intent intent) { - // Inflate a "Done"/"Cancel" custom action bar - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_save, + // Inflate a "Save"/"Cancel" custom action bar + ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_save, R.drawable.ic_action_save, new View.OnClickListener() { @Override public void onClick(View v) { saveClicked(); } - }, R.string.btn_do_not_save, new View.OnClickListener() { + }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { @Override public void onClick(View v) { cancelClicked(); @@ -150,7 +150,7 @@ public class EditKeyActivity extends ActionBarActivity { Bundle extras = intent.getExtras(); - mCurrentPassPhrase = ""; + mCurrentPassphrase = ""; if (extras != null) { // if userId is given, prefill the fields @@ -165,7 +165,7 @@ public class EditKeyActivity extends ActionBarActivity { if (noPassphrase) { // check "no passphrase" checkbox and remove button mNoPassphrase.setChecked(true); - mChangePassPhrase.setVisibility(View.GONE); + mChangePassphrase.setVisibility(View.GONE); } } @@ -181,13 +181,14 @@ public class EditKeyActivity extends ActionBarActivity { // fill values for this action Bundle data = new Bundle(); data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, - mCurrentPassPhrase); + mCurrentPassphrase); serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after generating is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( - this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER, true, + this, getResources().getQuantityString(R.plurals.progress_generating, 1), + ProgressDialog.STYLE_HORIZONTAL, true, new DialogInterface.OnCancelListener() { @Override @@ -224,7 +225,7 @@ public class EditKeyActivity extends ActionBarActivity { buildLayout(); } - }; + } }; // Create a new Messenger for the communication back @@ -248,8 +249,8 @@ public class EditKeyActivity extends ActionBarActivity { * @param intent */ private void handleActionEditKey(Intent intent) { - // Inflate a "Done"/"Cancel" custom action bar - ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_save, + // Inflate a "Save"/"Cancel" custom action bar + ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_save, R.drawable.ic_action_save, new View.OnClickListener() { @Override public void onClick(View v) { @@ -279,9 +280,9 @@ public class EditKeyActivity extends ActionBarActivity { @Override public void handleMessage(Message message) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - String passPhrase = PassphraseCacheService.getCachedPassphrase( + String passphrase = PassphraseCacheService.getCachedPassphrase( EditKeyActivity.this, masterKeyId); - mCurrentPassPhrase = passPhrase; + mCurrentPassphrase = passphrase; finallySaveClicked(); } } @@ -326,8 +327,8 @@ public class EditKeyActivity extends ActionBarActivity { cancelClicked(); return true; case R.id.menu_key_edit_export_file: - mExportHelper.showExportKeysDialog(mDataUri, Id.type.secret_key, Constants.path.APP_DIR - + "/secexport.asc"); + long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())}; + mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.path.APP_DIR_FILE_SEC); return true; case R.id.menu_key_edit_delete: { // Message is received after key is deleted @@ -371,14 +372,14 @@ public class EditKeyActivity extends ActionBarActivity { } } - mCurrentPassPhrase = ""; + mCurrentPassphrase = ""; buildLayout(); mIsPassPhraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId); if (!mIsPassPhraseSet) { // check "no passphrase" checkbox and remove button mNoPassphrase.setChecked(true); - mChangePassPhrase.setVisibility(View.GONE); + mChangePassphrase.setVisibility(View.GONE); } } @@ -408,7 +409,7 @@ public class EditKeyActivity extends ActionBarActivity { // set title based on isPassphraseSet() int title = -1; if (isPassphraseSet()) { - title = R.string.title_change_pass_phrase; + title = R.string.title_change_passphrase; } else { title = R.string.title_set_passphrase; } @@ -427,7 +428,7 @@ public class EditKeyActivity extends ActionBarActivity { setContentView(R.layout.edit_key_activity); // find views - mChangePassPhrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_pass_phrase); + mChangePassphrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_passphrase); mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase); // Build layout based on given userIds and keys @@ -447,7 +448,7 @@ public class EditKeyActivity extends ActionBarActivity { updatePassPhraseButtonText(); - mChangePassPhrase.setOnClickListener(new OnClickListener() { + mChangePassphrase.setOnClickListener(new OnClickListener() { public void onClick(View v) { showSetPassphraseDialog(); } @@ -462,10 +463,10 @@ public class EditKeyActivity extends ActionBarActivity { // remove passphrase mSavedNewPassPhrase = mNewPassPhrase; mNewPassPhrase = ""; - mChangePassPhrase.setVisibility(View.GONE); + mChangePassphrase.setVisibility(View.GONE); } else { mNewPassPhrase = mSavedNewPassPhrase; - mChangePassPhrase.setVisibility(View.VISIBLE); + mChangePassphrase.setVisibility(View.VISIBLE); } } }); @@ -504,7 +505,7 @@ public class EditKeyActivity extends ActionBarActivity { if (passphrase == null) { showPassphraseDialog(masterKeyId, masterCanSign); } else { - mCurrentPassPhrase = passphrase; + mCurrentPassphrase = passphrase; finallySaveClicked(); } } catch (PgpGeneralException e) { @@ -523,7 +524,7 @@ public class EditKeyActivity extends ActionBarActivity { // fill values for this action Bundle data = new Bundle(); data.putString(KeychainIntentService.SAVE_KEYRING_CURRENT_PASSPHRASE, - mCurrentPassPhrase); + mCurrentPassphrase); data.putString(KeychainIntentService.SAVE_KEYRING_NEW_PASSPHRASE, mNewPassPhrase); data.putStringArrayList(KeychainIntentService.SAVE_KEYRING_USER_IDS, getUserIds(mUserIdsView)); @@ -541,7 +542,7 @@ public class EditKeyActivity extends ActionBarActivity { // Message is received after saving is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - R.string.progress_saving, ProgressDialog.STYLE_HORIZONTAL) { + getString(R.string.progress_saving), ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); @@ -559,7 +560,7 @@ public class EditKeyActivity extends ActionBarActivity { setResult(RESULT_OK, data); finish(); } - }; + } }; // Create a new Messenger for the communication back @@ -694,7 +695,7 @@ public class EditKeyActivity extends ActionBarActivity { } private void updatePassPhraseButtonText() { - mChangePassPhrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase) + mChangePassphrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase) : getString(R.string.btn_set_passphrase)); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 9da6c1b9f..8f8952763 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -52,17 +52,21 @@ import android.os.Message; import android.os.Messenger; import android.view.View; import android.view.View.OnClickListener; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; import com.beardedhen.androidbootstrap.BootstrapButton; +import com.beardedhen.androidbootstrap.FontAwesomeText; import com.devspark.appmsg.AppMsg; public class EncryptActivity extends DrawerActivity { @@ -101,18 +105,24 @@ public class EncryptActivity extends DrawerActivity { private int mEncryptTarget; - private EditText mPassPhrase = null; - private EditText mPassPhraseAgain = null; + private EditText mPassphrase = null; + private EditText mPassphraseAgain = null; private CheckBox mAsciiArmor = null; private Spinner mFileCompression = null; private EditText mFilename = null; private CheckBox mDeleteAfter = null; + private CheckBox mShareAfter = null; private BootstrapButton mBrowse = null; private String mInputFilename = null; private String mOutputFilename = null; + private Integer mShortAnimationDuration = null; + private boolean mFileAdvancedSettingsVisible = false; + private TextView mFileAdvancedSettings = null; + private LinearLayout mFileAdvancedSettingsContainer = null; + private FontAwesomeText mAdvancedSettingsIcon; private boolean mAsciiArmorDemand = false; private boolean mOverrideAsciiArmor = false; @@ -147,6 +157,9 @@ public class EncryptActivity extends DrawerActivity { updateMode(); updateActionBarButtons(); + + // retrieve and cache the system's short animation time + mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); } /** @@ -436,14 +449,14 @@ public class EncryptActivity extends DrawerActivity { // 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)) { + String passphrase = mPassphrase.getText().toString(); + String passphraseAgain = mPassphraseAgain.getText().toString(); + if (!passphrase.equals(passphraseAgain)) { AppMsg.makeText(this, R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show(); return; } - gotPassPhrase = (passPhrase.length() != 0); + gotPassPhrase = (passphrase.length() != 0); if (!gotPassPhrase) { AppMsg.makeText(this, R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT) .show(); @@ -550,11 +563,11 @@ public class EncryptActivity extends DrawerActivity { if (mMode.getCurrentView().getId() == R.id.modeSymmetric) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); - String passPhrase = mPassPhrase.getText().toString(); - if (passPhrase.length() == 0) { - passPhrase = null; + String passphrase = mPassphrase.getText().toString(); + if (passphrase.length() == 0) { + passphrase = null; } - data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passPhrase); + data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase); } else { mSecretKeyIdToPass = mSecretKeyId; encryptionKeyIds = mEncryptionKeyIds; @@ -604,7 +617,7 @@ public class EncryptActivity extends DrawerActivity { // Message is received after encrypting is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - R.string.progress_encrypting, ProgressDialog.STYLE_HORIZONTAL) { + getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); @@ -650,6 +663,15 @@ public class EncryptActivity extends DrawerActivity { .newInstance(mInputFilename); deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); } + + if (mShareAfter.isChecked()) { + // Share encrypted file + Intent sendFileIntent = new Intent(Intent.ACTION_SEND); + sendFileIntent.setType("*/*"); + sendFileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(mOutputFilename)); + startActivity(Intent.createChooser(sendFileIntent, + getString(R.string.title_send_file))); + } break; default: @@ -659,8 +681,6 @@ public class EncryptActivity extends DrawerActivity { } } } - - ; }; // Create a new Messenger for the communication back @@ -766,8 +786,8 @@ public class EncryptActivity extends DrawerActivity { mMainUserId = (TextView) findViewById(R.id.mainUserId); mMainUserIdRest = (TextView) findViewById(R.id.mainUserIdRest); - mPassPhrase = (EditText) findViewById(R.id.passPhrase); - mPassPhraseAgain = (EditText) findViewById(R.id.passPhraseAgain); + 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. @@ -785,6 +805,50 @@ public class EncryptActivity extends DrawerActivity { } }); + mAdvancedSettingsIcon = (FontAwesomeText) findViewById(R.id.advancedSettingsIcon); + mFileAdvancedSettingsContainer = (LinearLayout) findViewById(R.id.fileAdvancedSettingsContainer); + mFileAdvancedSettings = (TextView) findViewById(R.id.advancedSettings); + + LinearLayout advancedSettingsControl = (LinearLayout) findViewById(R.id.advancedSettingsControl); + advancedSettingsControl.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mFileAdvancedSettingsVisible = !mFileAdvancedSettingsVisible; + if (mFileAdvancedSettingsVisible) { + mAdvancedSettingsIcon.setIcon("fa-chevron-down"); + mFileAdvancedSettingsContainer.setVisibility(View.VISIBLE); + AlphaAnimation animation = new AlphaAnimation(0f, 1f); + animation.setDuration(mShortAnimationDuration); + mFileAdvancedSettingsContainer.startAnimation(animation); + mFileAdvancedSettings.setText(R.string.btn_encryption_advanced_settings_hide); + + } else { + mAdvancedSettingsIcon.setIcon("fa-chevron-right"); + AlphaAnimation animation = new AlphaAnimation(1f, 0f); + animation.setDuration(mShortAnimationDuration); + animation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + // do nothing + } + + @Override + public void onAnimationEnd(Animation animation) { + // making sure that at the end the container is completely removed from view + mFileAdvancedSettingsContainer.setVisibility(View.GONE); + } + + @Override + public void onAnimationRepeat(Animation animation) { + // do nothing + } + }); + mFileAdvancedSettingsContainer.startAnimation(animation); + mFileAdvancedSettings.setText(R.string.btn_encryption_advanced_settings_show); + } + } + }); + mFileCompression = (Spinner) findViewById(R.id.fileCompression); Choice[] choices = new Choice[]{ new Choice(Id.choice.compression.none, getString(R.string.choice_none) + " (" @@ -809,6 +873,7 @@ public class EncryptActivity extends DrawerActivity { } mDeleteAfter = (CheckBox) findViewById(R.id.deleteAfterEncryption); + mShareAfter = (CheckBox) findViewById(R.id.shareAfterEncryption); mAsciiArmor = (CheckBox) findViewById(R.id.asciiArmour); mAsciiArmor.setChecked(Preferences.getPreferences(this).getDefaultAsciiArmour()); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index 9ccd7e088..ac8250bef 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -22,16 +22,11 @@ import java.util.ArrayList; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; -import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; -import android.widget.TextView; public class HelpActivity extends ActionBarActivity { public static final String EXTRA_SELECTED_TAB = "selectedTab"; @@ -64,19 +59,19 @@ public class HelpActivity extends ActionBarActivity { Bundle startBundle = new Bundle(); startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)), - HelpHtmlFragment.class, startBundle, (selectedTab == 0 ? true : false)); + HelpHtmlFragment.class, startBundle, (selectedTab == 0) ); Bundle nfcBundle = new Bundle(); nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)), - HelpHtmlFragment.class, nfcBundle, (selectedTab == 1 ? true : false)); + HelpHtmlFragment.class, nfcBundle, (selectedTab == 1) ); Bundle changelogBundle = new Bundle(); changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)), - HelpHtmlFragment.class, changelogBundle, (selectedTab == 2 ? true : false)); + HelpHtmlFragment.class, changelogBundle, (selectedTab == 2) ); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)), - HelpAboutFragment.class, null, (selectedTab == 3 ? true : false)); + HelpAboutFragment.class, null, (selectedTab == 3) ); } } \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 5ac421a44..f04a0e227 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -161,7 +161,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa } else if (extras.containsKey(EXTRA_KEY_ID)) { long keyId = intent.getLongExtra(EXTRA_KEY_ID, 0); if (keyId != 0) { - query = "0x" + PgpKeyHelper.convertKeyToHex(keyId); + query = PgpKeyHelper.convertKeyIdToHex(keyId); } } else if (extras.containsKey(EXTRA_FINGERPRINT)) { String fingerprint = intent.getStringExtra(EXTRA_FINGERPRINT); @@ -360,51 +360,53 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa // } - // Message is received after importing is done in ApgService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - R.string.progress_importing, ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard ApgHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - int added = returnData.getInt(KeychainIntentService.RESULT_IMPORT_ADDED); - int updated = returnData - .getInt(KeychainIntentService.RESULT_IMPORT_UPDATED); - int bad = returnData.getInt(KeychainIntentService.RESULT_IMPORT_BAD); - String toastMessage; - if (added > 0 && updated > 0) { - String addedStr = getResources().getQuantityString( - R.plurals.keys_added_and_updated_1, added, added); - String updatedStr = getResources().getQuantityString( - R.plurals.keys_added_and_updated_2, updated, updated); - toastMessage = addedStr + updatedStr; - } else if (added > 0) { - toastMessage = getResources().getQuantityString(R.plurals.keys_added, - added, added); - } else if (updated > 0) { - toastMessage = getResources().getQuantityString(R.plurals.keys_updated, - updated, updated); - } else { - toastMessage = getString(R.string.no_keys_added_or_updated); - } - AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO) - .show(); - if (bad > 0) { - BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad); - badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog"); - } - } - } - }; - /** * Import keys with mImportData */ public void importKeys() { + // Message is received after importing is done in ApgService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( + this, + getString(R.string.progress_importing), + ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); + + int added = returnData.getInt(KeychainIntentService.RESULT_IMPORT_ADDED); + int updated = returnData + .getInt(KeychainIntentService.RESULT_IMPORT_UPDATED); + int bad = returnData.getInt(KeychainIntentService.RESULT_IMPORT_BAD); + String toastMessage; + if (added > 0 && updated > 0) { + String addedStr = getResources().getQuantityString( + R.plurals.keys_added_and_updated_1, added, added); + String updatedStr = getResources().getQuantityString( + R.plurals.keys_added_and_updated_2, updated, updated); + toastMessage = addedStr + updatedStr; + } else if (added > 0) { + toastMessage = getResources().getQuantityString(R.plurals.keys_added, + added, added); + } else if (updated > 0) { + toastMessage = getResources().getQuantityString(R.plurals.keys_updated, + updated, updated); + } else { + toastMessage = getString(R.string.no_keys_added_or_updated); + } + AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO) + .show(); + if (bad > 0) { + BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad); + badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog"); + } + } + } + }; + if (mListFragment.getKeyBytes() != null || mListFragment.getDataUri() != null) { Log.d(Constants.TAG, "importKeys started"); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 1118f0264..a6917d6f4 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -219,27 +219,44 @@ public class ImportKeysListFragment extends ListFragment implements } else { setListShownNoAnimation(true); } + + Exception error = data.getError(); + switch (loader.getId()) { case LOADER_ID_BYTES: + + if(error == null){ + // No error + } else if(error instanceof ImportKeysListLoader.FileHasNoContent) { + AppMsg.makeText(getActivity(), R.string.error_import_file_no_content, + AppMsg.STYLE_ALERT).show(); + } else if(error instanceof ImportKeysListLoader.NonPgpPart) { + AppMsg.makeText(getActivity(), + ((ImportKeysListLoader.NonPgpPart) error).getCount() + " " + getResources(). + getQuantityString(R.plurals.error_import_non_pgp_part, + ((ImportKeysListLoader.NonPgpPart) error).getCount()), + new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.confirm)).show(); + } else { + AppMsg.makeText(getActivity(), R.string.error_generic_report_bug, + new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.alert)).show(); + } break; case LOADER_ID_SERVER_QUERY: - Exception error = data.getError(); - - if(error == null){ + if(error == null) { AppMsg.makeText( getActivity(), getResources().getQuantityString(R.plurals.keys_found, mAdapter.getCount(), mAdapter.getCount()), AppMsg.STYLE_INFO ).show(); - } else if(error instanceof KeyServer.InsufficientQuery){ + } else if(error instanceof KeyServer.InsufficientQuery) { AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query, AppMsg.STYLE_ALERT).show(); - }else if(error instanceof KeyServer.QueryException){ + } else if(error instanceof KeyServer.QueryException) { AppMsg.makeText(getActivity(), R.string.error_keyserver_query, AppMsg.STYLE_ALERT).show(); - }else if(error instanceof KeyServer.TooManyResponses){ + } else if(error instanceof KeyServer.TooManyResponses) { AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses, AppMsg.STYLE_ALERT).show(); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 0bbe2edb1..9eebbed64 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -59,8 +59,8 @@ public class KeyListActivity extends DrawerActivity { return true; case R.id.menu_key_list_export: - mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR - + "/pubexport.asc"); + // TODO fix this for unified keylist + mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB); return true; default: diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index ea37677d1..c4a694bba 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -19,11 +19,14 @@ package org.sufficientlysecure.keychain.ui; import java.util.HashMap; import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.helper.ExportHelper; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes; @@ -53,13 +56,21 @@ import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.SearchView; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.animation.AnimationUtils; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.Button; @@ -73,24 +84,37 @@ import com.beardedhen.androidbootstrap.BootstrapButton; * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses * StickyListHeaders library which does not extend upon ListView. */ -public class KeyListFragment extends Fragment implements AdapterView.OnItemClickListener, +public class KeyListFragment extends Fragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks { private KeyListAdapter mAdapter; private StickyListHeadersListView mStickyList; + // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 + boolean mListShown; + View mProgressContainer; + View mListContainer; + + private String mCurQuery; + private SearchView mSearchView; // empty list layout private BootstrapButton mButtonEmptyCreate; private BootstrapButton mButtonEmptyImport; + /** * Load custom layout with StickyListView from library */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.key_list_fragment, container, false); + View root = inflater.inflate(R.layout.key_list_fragment, container, false); - mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create); + mStickyList = (StickyListHeadersListView) root.findViewById(R.id.key_list_list); + mStickyList.setOnItemClickListener(this); + + + // empty view + mButtonEmptyCreate = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_create); mButtonEmptyCreate.setOnClickListener(new OnClickListener() { @Override @@ -102,8 +126,7 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick startActivityForResult(intent, 0); } }); - - mButtonEmptyImport = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_import); + mButtonEmptyImport = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_import); mButtonEmptyImport.setOnClickListener(new OnClickListener() { @Override @@ -114,7 +137,12 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick } }); - return view; + // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 + mListContainer = root.findViewById(R.id.key_list_list_container); + mProgressContainer = root.findViewById(R.id.key_list_progress_container); + mListShown = true; + + return root; } /** @@ -125,8 +153,6 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); - mStickyList.setOnItemClickListener(this); mStickyList.setAreHeadersSticky(true); mStickyList.setDrawingListUnderStickyHeader(false); @@ -137,7 +163,7 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick } // this view is made visible if no data is available - mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); + mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty)); /* * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only @@ -147,8 +173,6 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { - private int count = 0; - @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { android.view.MenuInflater inflater = getActivity().getMenuInflater(); @@ -174,7 +198,7 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick break; } case R.id.menu_key_list_multi_delete: { - ids = mAdapter.getCurrentSelectedItemIds(); + ids = mStickyList.getWrappedList().getCheckedItemIds(); showDeleteKeyDialog(mode, ids); break; } @@ -184,7 +208,6 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick @Override public void onDestroyActionMode(ActionMode mode) { - count = 0; mAdapter.clearSelection(); } @@ -192,13 +215,11 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { - count++; mAdapter.setNewSelection(position, checked); } else { - count--; mAdapter.removeSelection(position); } - + int count = mStickyList.getCheckedItemCount(); String keysSelected = getResources().getQuantityString( R.plurals.key_list_selected_keys, count, count); mode.setTitle(keysSelected); @@ -207,9 +228,12 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick }); } - // NOTE: Not supported by StickyListHeader, thus no indicator is shown while loading + // We have a menu item to show in action bar. + setHasOptionsMenu(true); + + // NOTE: Not supported by StickyListHeader, but reimplemented here // Start out with a progress indicator. - // setListShown(false); + setListShown(false); // Create an empty adapter we will use to display the loaded data. mAdapter = new KeyListAdapter(getActivity(), null, Id.type.public_key); @@ -238,27 +262,33 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); - + String where = null; + String whereArgs[] = null; + if (mCurQuery != null) { + where = KeychainContract.UserIds.USER_ID + " LIKE ?"; + whereArgs = new String[]{"%" + mCurQuery + "%"}; + } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, SORT_ORDER); + return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, SORT_ORDER); } @Override public void onLoadFinished(Loader loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) + mAdapter.setSearchQuery(mCurQuery); mAdapter.swapCursor(data); mStickyList.setAdapter(mAdapter); - // NOTE: Not supported by StickyListHeader, thus no indicator is shown while loading + // NOTE: Not supported by StickyListHeader, but reimplemented here // The list should now be shown. - // if (isResumed()) { - // setListShown(true); - // } else { - // setListShownNoAnimation(true); - // } + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } } @Override @@ -338,6 +368,87 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); } + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + // Get the searchview + MenuItem searchItem = menu.findItem(R.id.menu_key_list_search); + mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem); + + // Execute this when searching + mSearchView.setOnQueryTextListener(this); + + // Erase search result without focus + MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return true; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + mCurQuery = null; + mSearchView.setQuery("", true); + getLoaderManager().restartLoader(0, null, KeyListFragment.this); + return true; + } + }); + + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onQueryTextSubmit(String s) { + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurQuery = !TextUtils.isEmpty(s) ? s : null; + getLoaderManager().restartLoader(0, null, this); + return true; + } + + // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 + public void setListShown(boolean shown, boolean animate) { + if (mListShown == shown) { + return; + } + mListShown = shown; + if (shown) { + if (animate) { + mProgressContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_out)); + mListContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_in)); + } + mProgressContainer.setVisibility(View.GONE); + mListContainer.setVisibility(View.VISIBLE); + } else { + if (animate) { + mProgressContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_in)); + mListContainer.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_out)); + } + mProgressContainer.setVisibility(View.VISIBLE); + mListContainer.setVisibility(View.INVISIBLE); + } + } + + // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 + public void setListShown(boolean shown) { + setListShown(shown, true); + } + + // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 + public void setListShownNoAnimation(boolean shown) { + setListShown(shown, false); + } + /** * Implements StickyListHeadersAdapter from library */ @@ -347,6 +458,8 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick private int mIndexIsRevoked; private int mMasterKeyId; + private String mCurQuery; + @SuppressLint("UseSparseArrays") private HashMap mSelection = new HashMap(); @@ -394,12 +507,12 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick String userId = cursor.getString(mIndexUserId); String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[0] != null) { - mainUserId.setText(userIdSplit[0]); + mainUserId.setText(highlightSearchQuery(userIdSplit[0])); } else { mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); + mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); mainUserIdRest.setVisibility(View.VISIBLE); } else { mainUserIdRest.setVisibility(View.GONE); @@ -558,20 +671,6 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick notifyDataSetChanged(); } - public boolean isPositionChecked(int position) { - Boolean result = mSelection.get(position); - return result == null ? false : result; - } - - public long[] getCurrentSelectedItemIds() { - long[] ids = new long[mSelection.size()]; - int i = 0; - // get master key ids - for (int pos : mSelection.keySet()) - ids[i++] = mAdapter.getItemId(pos); - return ids; - } - public long[] getCurrentSelectedMasterKeyIds() { long[] ids = new long[mSelection.size()]; int i = 0; @@ -608,6 +707,34 @@ public class KeyListFragment extends Fragment implements AdapterView.OnItemClick return v; } + // search highlight methods + + public void setSearchQuery(String searchQuery) { + mCurQuery = searchQuery; + } + + public String getSearchQuery() { + return mCurQuery; + } + + protected Spannable highlightSearchQuery(String text) { + Spannable highlight = Spannable.Factory.getInstance().newSpannable(text); + + if (mCurQuery != null) { + Pattern pattern = Pattern.compile("(?i)" + mCurQuery); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + highlight.setSpan( + new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)), + matcher.start(), + matcher.end(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return highlight; + } else { + return highlight; + } + } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java index b38beebd1..2e8f25890 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java @@ -24,24 +24,27 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; +import android.annotation.SuppressLint; import android.content.Intent; +import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceActivity; +import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.support.v7.app.ActionBarActivity; +import java.util.List; + +@SuppressLint("NewApi") public class PreferencesActivity extends PreferenceActivity { - private IntegerListPreference mPassPhraseCacheTtl = null; - private IntegerListPreference mEncryptionAlgorithm = null; - private IntegerListPreference mHashAlgorithm = null; - private IntegerListPreference mMessageCompression = null; - private IntegerListPreference mFileCompression = null; - private CheckBoxPreference mAsciiArmour = null; - private CheckBoxPreference mForceV3Signatures = null; + + public final static String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN"; + public final static String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; + private PreferenceScreen mKeyServerPreference = null; - private Preferences mPreferences; + private static Preferences mPreferences; @Override protected void onCreate(Bundle savedInstanceState) { @@ -53,22 +56,218 @@ public class PreferencesActivity extends PreferenceActivity { // actionBar.setDisplayHomeAsUpEnabled(false); // actionBar.setHomeButtonEnabled(false); - addPreferencesFromResource(R.xml.preferences); + String action = getIntent().getAction(); - mPassPhraseCacheTtl = (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL); - mPassPhraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl()); - mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry()); - mPassPhraseCacheTtl + if (action != null && action.equals(ACTION_PREFS_GEN)) { + addPreferencesFromResource(R.xml.gen_preferences); + + initializePassPassPhraceCacheTtl( + (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL)); + + mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); + String servers[] = mPreferences.getKeyServers(); + mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, + servers.length, servers.length)); + mKeyServerPreference + .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(PreferencesActivity.this, + PreferencesKeyServerActivity.class); + intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, + mPreferences.getKeyServers()); + startActivityForResult(intent, Id.request.key_server_preference); + return false; + } + }); + + } else if (action != null && action.equals(ACTION_PREFS_ADV)) { + addPreferencesFromResource(R.xml.adv_preferences); + + initializeEncryptionAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM)); + + int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, + Id.choice.compression.zlib, Id.choice.compression.bzip2, }; + String[] entries = new String[] { + getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", + "ZIP (" + getString(R.string.compression_fast) + ")", + "ZLIB (" + getString(R.string.compression_fast) + ")", + "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; + String[] values = new String[valueIds.length]; + for (int i = 0; i < values.length; ++i) { + values[i] = "" + valueIds[i]; + } + + initializeHashAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM), + valueIds, entries, values); + + initializeMessageCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION), + valueIds, entries, values); + + initializeFileCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION), + entries, values); + + initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR)); + + initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES)); + + } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case Id.request.key_server_preference: { + if (resultCode == RESULT_CANCELED || data == null) { + return; + } + String servers[] = data + .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); + mPreferences.setKeyServers(servers); + mKeyServerPreference.setSummary(getResources().getQuantityString( + R.plurals.n_key_servers, servers.length, servers.length)); + break; + } + + default: { + super.onActivityResult(requestCode, resultCode, data); + break; + } + } + } + + /* Called only on Honeycomb and later */ + @Override + public void onBuildHeaders(List

target) { + super.onBuildHeaders(target); + loadHeadersFromResource(R.xml.preference_headers, target); + } + + /** This fragment shows the general preferences in android 3.0+ */ + public static class GeneralPrefsFragment extends PreferenceFragment { + + private PreferenceScreen mKeyServerPreference = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.gen_preferences); + + initializePassPassPhraceCacheTtl( + (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL)); + + mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); + String servers[] = mPreferences.getKeyServers(); + mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, + servers.length, servers.length)); + mKeyServerPreference + .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(getActivity(), + PreferencesKeyServerActivity.class); + intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, + mPreferences.getKeyServers()); + startActivityForResult(intent, Id.request.key_server_preference); + return false; + } + }); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case Id.request.key_server_preference: { + if (resultCode == RESULT_CANCELED || data == null) { + return; + } + String servers[] = data + .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); + mPreferences.setKeyServers(servers); + mKeyServerPreference.setSummary(getResources().getQuantityString( + R.plurals.n_key_servers, servers.length, servers.length)); + break; + } + + default: { + super.onActivityResult(requestCode, resultCode, data); + break; + } + } + } + } + + /** This fragment shows the advanced preferences in android 3.0+ */ + public static class AdvancedPrefsFragment extends PreferenceFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.adv_preferences); + + initializeEncryptionAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM)); + + int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, + Id.choice.compression.zlib, Id.choice.compression.bzip2, }; + String[] entries = new String[] { + getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", + "ZIP (" + getString(R.string.compression_fast) + ")", + "ZLIB (" + getString(R.string.compression_fast) + ")", + "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; + String[] values = new String[valueIds.length]; + for (int i = 0; i < values.length; ++i) { + values[i] = "" + valueIds[i]; + } + + initializeHashAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM), + valueIds, entries, values); + + initializeMessageCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION), + valueIds, entries, values); + + initializeFileCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION), + entries, values); + + initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR)); + + initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES)); + } + } + + protected boolean isValidFragment (String fragmentName) { + return AdvancedPrefsFragment.class.getName().equals(fragmentName) + || GeneralPrefsFragment.class.getName().equals(fragmentName) + || super.isValidFragment(fragmentName); + } + + private static void initializePassPassPhraceCacheTtl(final IntegerListPreference mPassphraseCacheTtl) { + mPassphraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl()); + mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry()); + mPassphraseCacheTtl .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { - mPassPhraseCacheTtl.setValue(newValue.toString()); - mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry()); + mPassphraseCacheTtl.setValue(newValue.toString()); + mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry()); mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString())); return false; } }); + } - mEncryptionAlgorithm = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM); + private static void initializeEncryptionAlgorithm(final IntegerListPreference mEncryptionAlgorithm) { int valueIds[] = { PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, @@ -93,8 +292,10 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mHashAlgorithm = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM); + private static void initializeHashAlgorithm + (final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) { valueIds = new int[] { HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, }; @@ -116,19 +317,10 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mMessageCompression = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION); - valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, - Id.choice.compression.zlib, Id.choice.compression.bzip2, }; - entries = new String[] { - getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", - "ZIP (" + getString(R.string.compression_fast) + ")", - "ZLIB (" + getString(R.string.compression_fast) + ")", - "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; - values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } + private static void initializeMessageCompression + (final IntegerListPreference mMessageCompression, int[] valueIds, String[] entries, String[] values) { mMessageCompression.setEntries(entries); mMessageCompression.setEntryValues(values); mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression()); @@ -143,8 +335,10 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mFileCompression = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION); + private static void initializeFileCompression + (final IntegerListPreference mFileCompression, String[] entries, String[] values) { mFileCompression.setEntries(entries); mFileCompression.setEntryValues(values); mFileCompression.setValue("" + mPreferences.getDefaultFileCompression()); @@ -157,8 +351,9 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mAsciiArmour = (CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR); + private static void initializeAsciiArmour(final CheckBoxPreference mAsciiArmour) { mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour()); mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { @@ -167,8 +362,9 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mForceV3Signatures = (CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES); + private static void initializeForceV3Signatures(final CheckBoxPreference mForceV3Signatures) { mForceV3Signatures.setChecked(mPreferences.getForceV3Signatures()); mForceV3Signatures .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @@ -178,43 +374,5 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); - - mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); - String servers[] = mPreferences.getKeyServers(); - mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, - servers.length, servers.length)); - mKeyServerPreference - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(PreferencesActivity.this, - PreferencesKeyServerActivity.class); - intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, - mPreferences.getKeyServers()); - startActivityForResult(intent, Id.request.key_server_preference); - return false; - } - }); } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case Id.request.key_server_preference: { - if (resultCode == RESULT_CANCELED || data == null) { - return; - } - String servers[] = data - .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); - mPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(getResources().getQuantityString( - R.plurals.n_key_servers, servers.length, servers.length)); - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - } -} +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java index b5ac739ae..50fec1ffc 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java @@ -50,14 +50,14 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O super.onCreate(savedInstanceState); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay, + ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, new View.OnClickListener() { @Override public void onClick(View v) { // ok okClicked(); } - }, R.string.btn_do_not_save, new View.OnClickListener() { + }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { @Override public void onClick(View v) { // cancel @@ -81,11 +81,11 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O Intent intent = getIntent(); String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS); if (servers != null) { - for (int i = 0; i < servers.length; ++i) { + for (String serv : servers) { KeyServerEditor view = (KeyServerEditor) mInflater.inflate( R.layout.key_server_editor, mEditors, false); view.setEditorListener(this); - view.setValue(servers[i]); + view.setValue(serv); mEditors.addView(view); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java index 86ae0073f..3c63628f7 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java @@ -46,14 +46,14 @@ public class SelectPublicKeyActivity extends ActionBarActivity { super.onCreate(savedInstanceState); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay, + ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, new View.OnClickListener() { @Override public void onClick(View v) { // ok okClicked(); } - }, R.string.btn_do_not_save, new View.OnClickListener() { + }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { @Override public void onClick(View v) { // cancel diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java index 59b46dd00..d320af451 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java @@ -30,7 +30,7 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; -import android.app.Activity; +import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.net.Uri; @@ -38,17 +38,35 @@ import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.LinearLayout; import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; -public class SelectPublicKeyFragment extends ListFragmentWorkaround implements +public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher, LoaderManager.LoaderCallbacks { public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids"; - private Activity mActivity; private SelectKeyCursorAdapter mAdapter; - private ListView mListView; - + private EditText mSearchView; private long mSelectedMasterKeyIds[]; + private String mCurQuery; + + // copied from ListFragment + static final int INTERNAL_EMPTY_ID = 0x00ff0001; + static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002; + static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003; + // added for search view + static final int SEARCH_ID = 0x00ff0004; /** * Creates new instance of this fragment @@ -67,10 +85,84 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mSelectedMasterKeyIds = getArguments().getLongArray(ARG_PRESELECTED_KEY_IDS); } + /** + * Copied from ListFragment and added EditText for search on top of list. + * We do not use a custom layout here, because this breaks the progress bar functionality + * of ListFragment. + * + * @param inflater + * @param container + * @param savedInstanceState + * @return + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final Context context = getActivity(); + + FrameLayout root = new FrameLayout(context); + + // ------------------------------------------------------------------ + + LinearLayout pframe = new LinearLayout(context); + pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID); + pframe.setOrientation(LinearLayout.VERTICAL); + pframe.setVisibility(View.GONE); + pframe.setGravity(Gravity.CENTER); + + ProgressBar progress = new ProgressBar(context, null, + android.R.attr.progressBarStyleLarge); + pframe.addView(progress, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + root.addView(pframe, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + // ------------------------------------------------------------------ + + FrameLayout lframe = new FrameLayout(context); + lframe.setId(INTERNAL_LIST_CONTAINER_ID); + + TextView tv = new TextView(getActivity()); + tv.setId(INTERNAL_EMPTY_ID); + tv.setGravity(Gravity.CENTER); + lframe.addView(tv, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + // Added for search view: linearLayout, mSearchView + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.VERTICAL); + + mSearchView = new EditText(context); + mSearchView.setId(SEARCH_ID); + mSearchView.setHint(R.string.menu_search); + mSearchView.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.ic_action_search), null, null, null); + + linearLayout.addView(mSearchView, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + ListView lv = new ListView(getActivity()); + lv.setId(android.R.id.list); + lv.setDrawSelectorOnTop(false); + linearLayout.addView(lv, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + lframe.addView(linearLayout, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + root.addView(lframe, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + // ------------------------------------------------------------------ + + root.setLayoutParams(new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + return root; + } + /** * Define Adapter and Loader on create of Activity */ @@ -78,16 +170,15 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - mActivity = getActivity(); - mListView = getListView(); - - mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); + getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); // Give some text to display if there is no data. In a real // application this would come from a resource. setEmptyText(getString(R.string.list_empty)); - mAdapter = new SelectKeyCursorAdapter(mActivity, null, 0, mListView, Id.type.public_key); + mSearchView.addTextChangedListener(this); + + mAdapter = new SelectKeyCursorAdapter(getActivity(), null, 0, getListView(), Id.type.public_key); setListAdapter(mAdapter); @@ -101,16 +192,16 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements /** * Selects items based on master key ids in list view - * + * * @param masterKeyIds */ private void preselectMasterKeyIds(long[] masterKeyIds) { if (masterKeyIds != null) { - for (int i = 0; i < mListView.getCount(); ++i) { + for (int i = 0; i < getListView().getCount(); ++i) { long keyId = mAdapter.getMasterKeyId(i); - for (int j = 0; j < masterKeyIds.length; ++j) { - if (keyId == masterKeyIds[j]) { - mListView.setItemChecked(i, true); + for (long masterKeyId : masterKeyIds) { + if (keyId == masterKeyId) { + getListView().setItemChecked(i, true); break; } } @@ -120,15 +211,15 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements /** * Returns all selected master key ids - * + * * @return */ public long[] getSelectedMasterKeyIds() { // mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key // ids! Vector vector = new Vector(); - for (int i = 0; i < mListView.getCount(); ++i) { - if (mListView.isItemChecked(i)) { + for (int i = 0; i < getListView().getCount(); ++i) { + if (getListView().isItemChecked(i)) { vector.add(mAdapter.getMasterKeyId(i)); } } @@ -144,13 +235,13 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements /** * Returns all selected user ids - * + * * @return */ public String[] getSelectedUserIds() { Vector userIds = new Vector(); - for (int i = 0; i < mListView.getCount(); ++i) { - if (mListView.isItemChecked(i)) { + for (int i = 0; i < getListView().getCount(); ++i) { + if (getListView().isItemChecked(i)) { userIds.add((String) mAdapter.getUserId(i)); } } @@ -168,7 +259,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements // These are the rows that we will retrieve. long now = new Date().getTime() / 1000; - String[] projection = new String[] { + String[] projection = new String[]{ KeyRings._ID, KeyRings.MASTER_KEY_ID, UserIds.USER_ID, @@ -185,7 +276,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements + Keys.CAN_ENCRYPT + " = '1' AND valid_keys." + Keys.CREATION + " <= '" + now + "' AND " + "(valid_keys." + Keys.EXPIRY + " IS NULL OR valid_keys." + Keys.EXPIRY + " >= '" + now + "')) AS " - + SelectKeyCursorAdapter.PROJECTION_ROW_VALID, }; + + SelectKeyCursorAdapter.PROJECTION_ROW_VALID,}; String inMasterKeyList = null; if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.length > 0) { @@ -199,37 +290,28 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements inMasterKeyList += ")"; } - // if (searchString != null && searchString.trim().length() > 0) { - // String[] chunks = searchString.trim().split(" +"); - // qb.appendWhere("(EXISTS (SELECT tmp." + UserIds._ID + " FROM " + UserIds.TABLE_NAME - // + " AS tmp WHERE " + "tmp." + UserIds.KEY_ID + " = " + Keys.TABLE_NAME + "." - // + Keys._ID); - // for (int i = 0; i < chunks.length; ++i) { - // qb.appendWhere(" AND tmp." + UserIds.USER_ID + " LIKE "); - // qb.appendWhereEscapeString("%" + chunks[i] + "%"); - // } - // qb.appendWhere("))"); - // - // if (inIdList != null) { - // qb.appendWhere(" OR (" + inIdList + ")"); - // } - // } - String orderBy = UserIds.USER_ID + " ASC"; if (inMasterKeyList != null) { // sort by selected master keys orderBy = inMasterKeyList + " DESC, " + orderBy; } + String where = null; + String whereArgs[] = null; + if (mCurQuery != null) { + where = UserIds.USER_ID + " LIKE ?"; + whereArgs = new String[]{"%" + mCurQuery + "%"}; + } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, projection, null, null, orderBy); + return new CursorLoader(getActivity(), baseUri, projection, where, whereArgs, orderBy); } @Override public void onLoadFinished(Loader loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) + mAdapter.setSearchQuery(mCurQuery); mAdapter.swapCursor(data); // The list should now be shown. @@ -250,4 +332,20 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements // longer using it. mAdapter.swapCursor(null); } + + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void afterTextChanged(Editable editable) { + mCurQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null; + getLoaderManager().restartLoader(0, null, this); + } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java index 6bcb84f46..c9129285e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java @@ -24,10 +24,13 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import android.Manifest; import android.app.Activity; +import android.app.ActivityOptions; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -40,6 +43,7 @@ public class SelectSecretKeyLayoutFragment extends Fragment { private TextView mKeyUserId; private TextView mKeyUserIdRest; + private TextView mKeyMasterKeyIdHex; private BootstrapButton mSelectKeyButton; private Boolean mFilterCertify; @@ -61,26 +65,52 @@ public class SelectSecretKeyLayoutFragment extends Fragment { public void selectKey(long secretKeyId) { if (secretKeyId == Id.key.none) { - mKeyUserId.setText(R.string.api_settings_no_key); + mKeyMasterKeyIdHex.setText(R.string.api_settings_no_key); mKeyUserIdRest.setText(""); + mKeyUserId.setVisibility(View.GONE); + mKeyUserIdRest.setVisibility(View.GONE); + } else { - String uid = getResources().getString(R.string.user_id_no_name); - String uidExtra = ""; PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId( getActivity(), secretKeyId); if (keyRing != null) { PGPSecretKey key = PgpKeyHelper.getMasterKey(keyRing); + String masterkeyIdHex = PgpKeyHelper.convertKeyIdToHex(secretKeyId); + if (key != null) { String userId = PgpKeyHelper.getMainUserIdSafe(getActivity(), key); - String chunks[] = userId.split(" <", 2); - uid = chunks[0]; - if (chunks.length > 1) { - uidExtra = "<" + chunks[1]; + + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); + String userName, userEmail; + + if (userIdSplit[0] != null) { + userName = userIdSplit[0]; + } else { + userName = getActivity().getResources().getString(R.string.user_id_no_name); } + + if (userIdSplit[1] != null) { + userEmail = userIdSplit[1]; + } else { + userEmail = getActivity().getResources().getString(R.string.error_user_id_no_email); + } + + mKeyMasterKeyIdHex.setText(masterkeyIdHex); + mKeyUserId.setText(userName); + mKeyUserIdRest.setText(userEmail); + mKeyUserId.setVisibility(View.VISIBLE); + mKeyUserIdRest.setVisibility(View.VISIBLE); + } else { + mKeyMasterKeyIdHex.setText(getActivity().getResources().getString(R.string.no_key)); + mKeyUserId.setVisibility(View.GONE); + mKeyUserIdRest.setVisibility(View.GONE); } + } else { + mKeyMasterKeyIdHex.setText(getActivity().getResources().getString(R.string.no_keys_added_or_updated) + " for master id: " + secretKeyId); + mKeyUserId.setVisibility(View.GONE); + mKeyUserIdRest.setVisibility(View.GONE); } - mKeyUserId.setText(uid); - mKeyUserIdRest.setText(uidExtra); + } } @@ -98,6 +128,7 @@ public class SelectSecretKeyLayoutFragment extends Fragment { mKeyUserId = (TextView) view.findViewById(R.id.select_secret_key_user_id); mKeyUserIdRest = (TextView) view.findViewById(R.id.select_secret_key_user_id_rest); + mKeyMasterKeyIdHex = (TextView) view.findViewById(R.id.select_secret_key_master_key_hex); mSelectKeyButton = (BootstrapButton) view .findViewById(R.id.select_secret_key_select_key_button); mFilterCertify = false; @@ -117,30 +148,31 @@ public class SelectSecretKeyLayoutFragment extends Fragment { startActivityForResult(intent, REQUEST_CODE_SELECT_KEY); } + // Select Secret Key Activity delivers the intent which was sent by it using interface to Select + // Secret Key Fragment.Intent contains Master Key Id, User Email, User Name, Master Key Id Hex. @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode & 0xFFFF) { - case REQUEST_CODE_SELECT_KEY: { - long secretKeyId; - if (resultCode == Activity.RESULT_OK) { - Bundle bundle = data.getExtras(); - secretKeyId = bundle.getLong(SelectSecretKeyActivity.RESULT_EXTRA_MASTER_KEY_ID); + case REQUEST_CODE_SELECT_KEY: { + long secretKeyId; + if (resultCode == Activity.RESULT_OK) { + Bundle bundle = data.getExtras(); + secretKeyId = bundle.getLong(SelectSecretKeyActivity.RESULT_EXTRA_MASTER_KEY_ID); + selectKey(secretKeyId); - selectKey(secretKeyId); + // remove displayed errors + mKeyUserId.setError(null); - // remove displayed errors - mKeyUserId.setError(null); - - // give value back to callback - mCallback.onKeySelected(secretKeyId); + // give value back to callback + mCallback.onKeySelected(secretKeyId); + } + break; } - break; - } - default: - super.onActivityResult(requestCode, resultCode, data); + default: + super.onActivityResult(requestCode, resultCode, data); - break; + break; } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 550d3047d..6f0aaa0f0 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -102,7 +102,7 @@ public class UploadKeyActivity extends ActionBarActivity { // Message is received after uploading is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - R.string.progress_exporting, ProgressDialog.STYLE_HORIZONTAL) { + getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); @@ -113,7 +113,7 @@ public class UploadKeyActivity extends ActionBarActivity { Toast.LENGTH_SHORT).show(); finish(); } - }; + } }; // Create a new Messenger for the communication back diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 055203c0f..01a2740b1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -93,12 +93,12 @@ public class ViewKeyActivity extends ActionBarActivity { Bundle mainBundle = new Bundle(); mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_main)), - ViewKeyMainFragment.class, mainBundle, (selectedTab == 0 ? true : false)); + ViewKeyMainFragment.class, mainBundle, (selectedTab == 0)); Bundle certBundle = new Bundle(); certBundle.putLong(ViewKeyCertsFragment.ARG_KEYRING_ROW_ID, rowId); mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_certs)), - ViewKeyCertsFragment.class, certBundle, (selectedTab == 1 ? true : false)); + ViewKeyCertsFragment.class, certBundle, (selectedTab == 1)); } @Override @@ -123,8 +123,8 @@ public class ViewKeyActivity extends ActionBarActivity { uploadToKeyserver(mDataUri); return true; case R.id.menu_key_view_export_file: - mExportHelper.showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR - + "/pubexport.asc"); + long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())}; + mExportHelper.showExportKeysDialog(ids, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB); return true; case R.id.menu_key_view_share_default_fingerprint: shareKey(mDataUri, true); @@ -159,7 +159,7 @@ public class ViewKeyActivity extends ActionBarActivity { } private void updateFromKeyserver(Uri dataUri) { - long updateKeyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, mDataUri); + long updateKeyId = ProviderHelper.getMasterKeyId(ViewKeyActivity.this, dataUri); if (updateKeyId == 0) { Log.e(Constants.TAG, "this shouldn't happen. KeyId == 0!"); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 00ca0d1f4..c898a06ea 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -26,7 +26,10 @@ import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.text.Spannable; +import android.text.SpannableStringBuilder; import android.text.format.DateFormat; +import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -273,7 +276,7 @@ public class ViewKeyMainFragment extends Fragment implements // get key id from MASTER_KEY_ID long keyId = data.getLong(KEYS_INDEX_KEY_ID); - String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(keyId); mKeyId.setText(keyIdStr); // get creation date from CREATION @@ -306,9 +309,8 @@ public class ViewKeyMainFragment extends Fragment implements fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), mDataUri); } String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, true); - fingerprint = fingerprint.replace(" ", "\n"); - mFingerprint.setText(fingerprint); + mFingerprint.setText(colorizeFingerprint(fingerprint)); } mKeysAdapter.swapCursor(data); @@ -319,6 +321,25 @@ public class ViewKeyMainFragment extends Fragment implements } } + private SpannableStringBuilder colorizeFingerprint(String fingerprint) { + SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint); + ForegroundColorSpan fcs = new ForegroundColorSpan(Color.BLACK); + + // for each 4 characters of the fingerprint + 1 space + for (int i = 0; i < fingerprint.length(); i += 5) { + int minFingLength = Math.min(i + 4, fingerprint.length()); + String fourChars = fingerprint.substring(i, minFingLength); + + // Create a foreground color by converting the 4 fingerprint chars to an int hashcode + // and then converting that int to hex to use as a color + fcs = new ForegroundColorSpan( + Color.parseColor(String.format("#%06X", (0xFFFFFF & fourChars.hashCode())))); + sb.setSpan(fcs, i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + + return sb; + } + /** * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. * We need to make sure we are no longer using it. diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java new file mode 100644 index 000000000..fd7a2dc30 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.ui.adapter; + +import android.content.Context; +import android.database.Cursor; +import android.support.v4.widget.CursorAdapter; +import android.text.Spannable; +import android.text.style.ForegroundColorSpan; + +import org.sufficientlysecure.keychain.R; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class HighlightQueryCursorAdapter extends CursorAdapter { + + private String mCurQuery; + + public HighlightQueryCursorAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + mCurQuery = null; + } + + public void setSearchQuery(String searchQuery) { + mCurQuery = searchQuery; + } + + public String getSearchQuery() { + return mCurQuery; + } + + protected Spannable highlightSearchQuery(String text) { + Spannable highlight = Spannable.Factory.getInstance().newSpannable(text); + + if (mCurQuery != null) { + Pattern pattern = Pattern.compile("(?i)" + mCurQuery); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + highlight.setSpan( + new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)), + matcher.start(), + matcher.end(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return highlight; + } else { + return highlight; + } + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 52186b662..4f7623bce 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -42,7 +42,15 @@ public class ImportKeysAdapter extends ArrayAdapter { protected Activity mActivity; protected List data; + static class ViewHolder{ + private TextView mainUserId; + private TextView mainUserIdRest; + private TextView keyId; + private TextView fingerprint; + private TextView algorithm; + private TextView status; + } public ImportKeysAdapter(Activity activity) { super(activity, -1); mActivity = activity; @@ -86,16 +94,21 @@ public class ImportKeysAdapter extends ArrayAdapter { public View getView(int position, View convertView, ViewGroup parent) { ImportKeysListEntry entry = data.get(position); - - View view = mInflater.inflate(R.layout.import_keys_list_entry, null); - - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - TextView keyId = (TextView) view.findViewById(R.id.keyId); - TextView fingerprint = (TextView) view.findViewById(R.id.fingerprint); - TextView algorithm = (TextView) view.findViewById(R.id.algorithm); - TextView status = (TextView) view.findViewById(R.id.status); - + ViewHolder holder; + if(convertView == null) { + holder = new ViewHolder(); + convertView = mInflater.inflate(R.layout.import_keys_list_entry, null); + holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId); + holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest); + holder.keyId = (TextView) convertView.findViewById(R.id.keyId); + holder.fingerprint = (TextView) convertView.findViewById(R.id.fingerprint); + holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm); + holder.status = (TextView) convertView.findViewById(R.id.status); + convertView.setTag(holder); + } + else{ + holder = (ViewHolder)convertView.getTag(); + } // main user id String userId = entry.userIds.get(0); String[] userIdSplit = PgpKeyHelper.splitUserId(userId); @@ -105,39 +118,39 @@ public class ImportKeysAdapter extends ArrayAdapter { // show red user id if it is a secret key if (entry.secretKey) { userIdSplit[0] = mActivity.getString(R.string.secret_key) + " " + userIdSplit[0]; - mainUserId.setTextColor(Color.RED); + holder.mainUserId.setTextColor(Color.RED); } - mainUserId.setText(userIdSplit[0]); + holder.mainUserId.setText(userIdSplit[0]); } else { - mainUserId.setText(R.string.user_id_no_name); + holder.mainUserId.setText(R.string.user_id_no_name); } // email if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); - mainUserIdRest.setVisibility(View.VISIBLE); + holder.mainUserIdRest.setText(userIdSplit[1]); + holder.mainUserIdRest.setVisibility(View.VISIBLE); } else { - mainUserIdRest.setVisibility(View.GONE); + holder.mainUserIdRest.setVisibility(View.GONE); } - keyId.setText(entry.hexKeyId); + holder.keyId.setText(entry.hexKeyId); if (entry.fingerPrint != null) { - fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint); - fingerprint.setVisibility(View.VISIBLE); + holder.fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint); + holder.fingerprint.setVisibility(View.VISIBLE); } else { - fingerprint.setVisibility(View.GONE); + holder.fingerprint.setVisibility(View.GONE); } - algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); + holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); if (entry.revoked) { - status.setText(R.string.revoked); + holder.status.setText(R.string.revoked); } else { - status.setVisibility(View.GONE); + holder.status.setVisibility(View.GONE); } - LinearLayout ll = (LinearLayout) view.findViewById(R.id.list); + LinearLayout ll = (LinearLayout) convertView.findViewById(R.id.list); if (entry.userIds.size() == 1) { ll.setVisibility(View.GONE); } else { @@ -162,10 +175,10 @@ public class ImportKeysAdapter extends ArrayAdapter { } } - CheckBox cBox = (CheckBox) view.findViewById(R.id.selected); + CheckBox cBox = (CheckBox) convertView.findViewById(R.id.selected); cBox.setChecked(entry.isSelected()); - return view; + return convertView; } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java index 4a7a9c93a..a52e9b447 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java @@ -125,7 +125,10 @@ public class ImportKeysListEntry implements Serializable, Parcelable { * Constructor for later querying from keyserver */ public ImportKeysListEntry() { + // keys from keyserver are always public keys secretKey = false; + // do not select by default + selected = false; userIds = new ArrayList(); } @@ -167,7 +170,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { this.revoked = pgpKeyRing.getPublicKey().isRevoked(); this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() .getFingerprint(), true); - this.hexKeyId = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); + this.hexKeyId = PgpKeyHelper.convertKeyIdToHex(keyId); this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength(); int algorithm = pgpKeyRing.getPublicKey().getAlgorithm(); if (algorithm == PGPPublicKey.RSA_ENCRYPT || algorithm == PGPPublicKey.RSA_GENERAL diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 29e418db7..3eca99f15 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui.adapter; import java.io.BufferedInputStream; import java.io.InputStream; import java.util.ArrayList; -import java.util.List; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; @@ -34,6 +33,21 @@ import android.content.Context; import android.support.v4.content.AsyncTaskLoader; public class ImportKeysListLoader extends AsyncTaskLoader>> { + + public static class FileHasNoContent extends Exception { + + } + + public static class NonPgpPart extends Exception { + private int count; + public NonPgpPart(int count) { + this.count = count; + } + public int getCount() { + return count; + } + } + Context mContext; InputData mInputData; @@ -88,21 +102,26 @@ public class ImportKeysListLoader extends AsyncTaskLoader 0) { + isEmpty = false; InputStream in = PGPUtil.getDecoderStream(bufferedInput); PGPObjectFactory objectFactory = new PGPObjectFactory(in); @@ -116,11 +135,25 @@ public class ImportKeysListLoader extends AsyncTaskLoader>(data, e); + nonPgpCounter = 0; + } + + if(isEmpty) { + Log.e(Constants.TAG, "File has no content!", new FileHasNoContent()); + entryListWrapper = new AsyncTaskResultWrapper> + (data, new FileHasNoContent()); + } + + if(nonPgpCounter > 0) { + entryListWrapper = new AsyncTaskResultWrapper> + (data, new NonPgpPart(nonPgpCounter)); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index d44dd5890..6d67a0e65 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -25,7 +25,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import android.content.Context; import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -33,7 +32,9 @@ import android.widget.CheckBox; import android.widget.ListView; import android.widget.TextView; -public class SelectKeyCursorAdapter extends CursorAdapter { + + +public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter { protected int mKeyType; @@ -55,7 +56,6 @@ public class SelectKeyCursorAdapter extends CursorAdapter { mInflater = LayoutInflater.from(context); mListView = listView; mKeyType = keyType; - initIndex(c); } @@ -104,12 +104,12 @@ public class SelectKeyCursorAdapter extends CursorAdapter { String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[0] != null) { - mainUserId.setText(userIdSplit[0]); + mainUserId.setText(highlightSearchQuery(userIdSplit[0])); } else { mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); + mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); } else { mainUserIdRest.setText(""); } @@ -164,5 +164,4 @@ public class SelectKeyCursorAdapter extends CursorAdapter { public View newView(Context context, Cursor cursor, ViewGroup parent) { return mInflater.inflate(R.layout.select_key_item, null); } - } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java index 54c7eb60e..046a98883 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java @@ -83,7 +83,7 @@ public class ViewKeyKeysAdapter extends CursorAdapter { ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); - String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm), cursor.getInt(mIndexKeySize)); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java index 98b677511..a47601c9b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java @@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.Choice; +import java.util.ArrayList; import java.util.Vector; public class CreateKeyDialogFragment extends DialogFragment { @@ -78,7 +79,7 @@ public class CreateKeyDialogFragment extends DialogFragment { boolean wouldBeMasterKey = (childCount == 0); final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm); - Vector choices = new Vector(); + ArrayList choices = new ArrayList(); choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString( R.string.dsa))); if (!wouldBeMasterKey) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index cd8bc79a9..162bf32fd 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -67,7 +67,7 @@ public class DeleteFileDialogFragment extends DialogFragment { alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile)); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - + @Override public void onClick(DialogInterface dialog, int id) { dismiss(); @@ -83,7 +83,10 @@ public class DeleteFileDialogFragment extends DialogFragment { intent.putExtra(KeychainIntentService.EXTRA_DATA, data); ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance( - R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL, false, null); + getString(R.string.progress_deleting_securely), + ProgressDialog.STYLE_HORIZONTAL, + false, + null); // Message is received after deleting is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) { @@ -95,7 +98,7 @@ public class DeleteFileDialogFragment extends DialogFragment { Toast.makeText(activity, R.string.file_delete_successful, Toast.LENGTH_SHORT).show(); } - }; + } }; // Create a new Messenger for the communication back diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java index 39ce63b5f..2a3a7508d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java @@ -33,7 +33,6 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.v4.app.DialogFragment; -import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java index e88271240..afa05cc91 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java @@ -153,17 +153,17 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor dismiss(); long curKeyIndex = 1; boolean keyOK = true; - String passPhrase = mPassphraseEditText.getText().toString(); + String passphrase = mPassphraseEditText.getText().toString(); long keyId; PGPSecretKey clickSecretKey = secretKey; if (clickSecretKey != null) { - while (keyOK == true) { + while (keyOK) { if (clickSecretKey != null) { // check again for loop try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - passPhrase.toCharArray()); + passphrase.toCharArray()); PGPPrivateKey testKey = clickSecretKey .extractPrivateKey(keyDecryptor); if (testKey == null) { @@ -206,10 +206,10 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor // cache the new passphrase Log.d(Constants.TAG, "Everything okay! Caching entered passphrase"); - PassphraseCacheService.addCachedPassphrase(activity, keyId, passPhrase); - if (keyOK == false && clickSecretKey.getKeyID() != keyId) { + PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase); + if ( !keyOK && clickSecretKey.getKeyID() != keyId) { PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(), - passPhrase); + passphrase); } sendMessageToHandler(MESSAGE_OKAY); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java index 6c62d14e0..b7a1882ef 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java @@ -30,7 +30,7 @@ import android.view.KeyEvent; import org.sufficientlysecure.keychain.R; public class ProgressDialogFragment extends DialogFragment { - private static final String ARG_MESSAGE_ID = "message_id"; + private static final String ARG_MESSAGE = "message"; private static final String ARG_STYLE = "style"; private static final String ARG_CANCELABLE = "cancelable"; @@ -39,16 +39,16 @@ public class ProgressDialogFragment extends DialogFragment { /** * Creates new instance of this fragment * - * @param messageId + * @param message * @param style * @param cancelable * @return */ - public static ProgressDialogFragment newInstance(int messageId, int style, boolean cancelable, + public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable, OnCancelListener onCancelListener) { ProgressDialogFragment frag = new ProgressDialogFragment(); Bundle args = new Bundle(); - args.putInt(ARG_MESSAGE_ID, messageId); + args.putString(ARG_MESSAGE, message); args.putInt(ARG_STYLE, style); args.putBoolean(ARG_CANCELABLE, cancelable); @@ -117,22 +117,22 @@ public class ProgressDialogFragment extends DialogFragment { dialog.setCancelable(false); dialog.setCanceledOnTouchOutside(false); - int messageId = getArguments().getInt(ARG_MESSAGE_ID); + String message = getArguments().getString(ARG_MESSAGE); int style = getArguments().getInt(ARG_STYLE); boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE); - dialog.setMessage(getString(messageId)); + dialog.setMessage(message); dialog.setProgressStyle(style); if (cancelable) { dialog.setButton(DialogInterface.BUTTON_NEGATIVE, activity.getString(R.string.progress_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); } // Disable the back button @@ -140,7 +140,6 @@ public class ProgressDialogFragment extends DialogFragment { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { return true; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index 50e72dfba..e406547b3 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -101,9 +101,9 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi public void onClick(DialogInterface dialog, int id) { dismiss(); - String passPhrase1 = mPassphraseEditText.getText().toString(); - String passPhrase2 = mPassphraseAgainEditText.getText().toString(); - if (!passPhrase1.equals(passPhrase2)) { + String passphrase1 = mPassphraseEditText.getText().toString(); + String passphrase2 = mPassphraseAgainEditText.getText().toString(); + if (!passphrase1.equals(passphrase2)) { Toast.makeText( activity, getString(R.string.error_message, @@ -112,7 +112,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi return; } - if (passPhrase1.equals("")) { + if (passphrase1.equals("")) { Toast.makeText( activity, getString(R.string.error_message, @@ -123,7 +123,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi // return resulting data back to activity Bundle data = new Bundle(); - data.putString(MESSAGE_NEW_PASSPHRASE, passPhrase1); + data.putString(MESSAGE_NEW_PASSPHRASE, passphrase1); sendMessageToHandler(MESSAGE_OKAY, data); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java index 03e09cdcb..b850638a6 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java @@ -53,7 +53,6 @@ public class ShareNfcDialogFragment extends DialogFragment { AlertDialog.Builder alert = new AlertDialog.Builder(activity); - alert.setIcon(android.R.drawable.ic_dialog_info); alert.setTitle(R.string.share_nfc_dialog); alert.setCancelable(true); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 6c265057e..65461cb4f 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -34,6 +34,7 @@ import android.app.DatePickerDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.text.format.DateUtils; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; @@ -58,6 +59,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { Spinner mUsage; TextView mCreationDate; BootstrapButton mExpiryDateButton; + GregorianCalendar mCreatedDate; GregorianCalendar mExpiryDate; private int mDatePickerResultCount = 0; @@ -113,8 +115,12 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { if (date == null) { date = new GregorianCalendar(TimeZone.getTimeZone("UTC")); } - - DatePickerDialog dialog = new DatePickerDialog(getContext(), + /* + * Using custom DatePickerDialog which overrides the setTitle because + * the DatePickerDialog title is buggy (unix warparound bug). + * See: https://code.google.com/p/android/issues/detail?id=49066 + */ + DatePickerDialog dialog = new ExpiryDatePickerDialog(getContext(), mExpiryDateSetListener, date.get(Calendar.YEAR), date.get(Calendar.MONTH), date.get(Calendar.DAY_OF_MONTH)); mDatePickerResultCount = 0; @@ -129,6 +135,21 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } } }); + + // setCalendarViewShown() is supported from API 11 onwards. + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) + // Hide calendarView in tablets because of the unix warparound bug. + dialog.getDatePicker().setCalendarViewShown(false); + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + if ( dialog != null && mCreatedDate != null ) { + dialog.getDatePicker().setMinDate(mCreatedDate.getTime().getTime()+ DateUtils.DAY_IN_MILLIS); + } else { + //When created date isn't available + dialog.getDatePicker().setMinDate(date.getTime().getTime()+ DateUtils.DAY_IN_MILLIS); + } + } + dialog.show(); } }); @@ -153,9 +174,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(key)); - String keyId1Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID()); - String keyId2Str = PgpKeyHelper.convertKeyIdToHex(key.getKeyID() >> 32); - mKeyId.setText(keyId1Str + " " + keyId2Str); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(key.getKeyID()); + mKeyId.setText(keyIdStr); Vector choices = new Vector(); boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT); @@ -205,7 +225,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); cal.setTime(PgpKeyHelper.getCreationDate(key)); - mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime())); + setCreatedDate(cal); cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); Date expiryDate = PgpKeyHelper.getExpiryDate(key); if (expiryDate == null) { @@ -235,6 +255,15 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { mEditorListener = listener; } + private void setCreatedDate(GregorianCalendar date) { + mCreatedDate = date; + if (date == null) { + mCreationDate.setText(getContext().getString(R.string.none)); + } else { + mCreationDate.setText(DateFormat.getDateInstance().format(date.getTime())); + } + } + private void setExpiryDate(GregorianCalendar date) { mExpiryDate = date; if (date == null) { @@ -253,3 +282,14 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } } + +class ExpiryDatePickerDialog extends DatePickerDialog { + + public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { + super(context, callBack, year, monthOfYear, dayOfMonth); + } + //Set permanent title. + public void setTitle(CharSequence title) { + super.setTitle(getContext().getString(R.string.expiry_date_dialog_title)); + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index a95d80a4e..0acfe13bc 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -80,19 +80,19 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor public void setType(int type) { mType = type; switch (type) { - case Id.type.user_id: { - mTitle.setText(R.string.section_user_ids); - break; - } + case Id.type.user_id: { + mTitle.setText(R.string.section_user_ids); + break; + } - case Id.type.key: { - mTitle.setText(R.string.section_keys); - break; - } + case Id.type.key: { + mTitle.setText(R.string.section_keys); + break; + } - default: { - break; - } + default: { + break; + } } } @@ -103,7 +103,9 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor } } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ @Override protected void onFinishInflate() { mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -121,7 +123,9 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor super.onFinishInflate(); } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ public void onDeleted(Editor editor) { this.updateEditorsVisible(); } @@ -131,38 +135,40 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE); } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ public void onClick(View v) { if (canEdit) { switch (mType) { - case Id.type.user_id: { - UserIdEditor view = (UserIdEditor) mInflater.inflate( - R.layout.edit_key_user_id_item, mEditors, false); - view.setEditorListener(this); - if (mEditors.getChildCount() == 0) { - view.setIsMainUserId(true); - } - mEditors.addView(view); - break; - } - - case Id.type.key: { - CreateKeyDialogFragment mCreateKeyDialogFragment = CreateKeyDialogFragment.newInstance(mEditors.getChildCount()); - mCreateKeyDialogFragment.setOnAlgorithmSelectedListener(new CreateKeyDialogFragment.OnAlgorithmSelectedListener() { - @Override - public void onAlgorithmSelected(Choice algorithmChoice, int keySize) { - mNewKeyAlgorithmChoice = algorithmChoice; - mNewKeySize = keySize; - createKey(); + case Id.type.user_id: { + UserIdEditor view = (UserIdEditor) mInflater.inflate( + R.layout.edit_key_user_id_item, mEditors, false); + view.setEditorListener(this); + if (mEditors.getChildCount() == 0) { + view.setIsMainUserId(true); } - }); - mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog"); - break; - } + mEditors.addView(view); + break; + } - default: { - break; - } + case Id.type.key: { + CreateKeyDialogFragment mCreateKeyDialogFragment = CreateKeyDialogFragment.newInstance(mEditors.getChildCount()); + mCreateKeyDialogFragment.setOnAlgorithmSelectedListener(new CreateKeyDialogFragment.OnAlgorithmSelectedListener() { + @Override + public void onAlgorithmSelected(Choice algorithmChoice, int keySize) { + mNewKeyAlgorithmChoice = algorithmChoice; + mNewKeySize = keySize; + createKey(); + } + }); + mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog"); + break; + } + + default: { + break; + } } this.updateEditorsVisible(); } @@ -220,31 +226,34 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor Bundle data = new Bundle(); Boolean isMasterKey; - String passPhrase; + String passphrase; if (mEditors.getChildCount() > 0) { PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); - passPhrase = PassphraseCacheService + passphrase = PassphraseCacheService .getCachedPassphrase(mActivity, masterKey.getKeyID()); isMasterKey = false; } else { - passPhrase = ""; + passphrase = ""; isMasterKey = true; } data.putBoolean(KeychainIntentService.GENERATE_KEY_MASTER_KEY, isMasterKey); - data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passPhrase); + data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase); data.putInt(KeychainIntentService.GENERATE_KEY_ALGORITHM, mNewKeyAlgorithmChoice.getId()); data.putInt(KeychainIntentService.GENERATE_KEY_KEY_SIZE, mNewKeySize); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // show progress dialog - mGeneratingDialog = ProgressDialogFragment.newInstance(R.string.progress_generating, - ProgressDialog.STYLE_SPINNER, true, new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - mActivity.stopService(intent); - } - }); + mGeneratingDialog = ProgressDialogFragment.newInstance( + getResources().getQuantityString(R.plurals.progress_generating, 1), + ProgressDialog.STYLE_SPINNER, + true, + new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + mActivity.stopService(intent); + } + }); // Message is received after generating is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity, @@ -261,7 +270,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); addGeneratedKeyToView(newKey); } - }; + } }; // Create a new Messenger for the communication back diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java index 5428b626e..71cd89ae8 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui.widget; import java.util.regex.Matcher; import java.util.regex.Pattern; +import android.widget.*; import org.sufficientlysecure.keychain.R; import android.content.Context; @@ -26,11 +27,9 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.RadioButton; import com.beardedhen.androidbootstrap.BootstrapButton; +import org.sufficientlysecure.keychain.helper.ContactHelper; public class UserIdEditor extends LinearLayout implements Editor, OnClickListener { private EditorListener mEditorListener = null; @@ -38,7 +37,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene private BootstrapButton mDeleteButton; private RadioButton mIsMainUserId; private EditText mName; - private EditText mEmail; + private AutoCompleteTextView mEmail; private EditText mComment; // see http://www.regular-expressions.info/email.html @@ -102,9 +101,17 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene mIsMainUserId.setOnClickListener(this); mName = (EditText) findViewById(R.id.name); - mEmail = (EditText) findViewById(R.id.email); + mEmail = (AutoCompleteTextView) findViewById(R.id.email); mComment = (EditText) findViewById(R.id.comment); + + mEmail.setThreshold(1); // Start working from first character + mEmail.setAdapter( + new ArrayAdapter + (this.getContext(), android.R.layout.simple_dropdown_item_1line, + ContactHelper.getMailAccounts(getContext()) + )); + super.onFinishInflate(); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java index b94c42e90..32266839c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java @@ -1,6 +1,8 @@ /* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2011 Thialfihar * Copyright (C) 2011 Senecaso - * + * * 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 @@ -224,7 +226,7 @@ public class HkpKeyServer extends KeyServer { HttpClient client = new DefaultHttpClient(); try { HttpGet get = new HttpGet("http://" + mHost + ":" + mPort - + "/pks/lookup?op=get&search=0x" + PgpKeyHelper.convertKeyToHex(keyId)); + + "/pks/lookup?op=get&search=" + PgpKeyHelper.convertKeyIdToHex(keyId)); HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java index 072affb1f..7049820e8 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java @@ -1,6 +1,8 @@ /* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2011 Thialfihar * Copyright (C) 2011 Senecaso - * + * * 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 @@ -16,14 +18,8 @@ package org.sufficientlysecure.keychain.util; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; import java.util.List; -import android.os.Parcel; -import android.os.Parcelable; - import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; public abstract class KeyServer { @@ -52,5 +48,5 @@ public abstract class KeyServer { abstract String get(long keyId) throws QueryException; - abstract void add(String armouredText) throws AddKeyException; + abstract void add(String armoredText) throws AddKeyException; } diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_save.png new file mode 100644 index 000000000..c4b7783cc Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_save.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_search.png new file mode 100644 index 000000000..f594b4e48 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_search.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_secure.png new file mode 100644 index 000000000..287ae2fb0 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_secure.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_select_all.png new file mode 100644 index 000000000..fc0dd57b6 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_select_all.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_save.png new file mode 100644 index 000000000..61304a68c Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_save.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_search.png new file mode 100644 index 000000000..f6719d228 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_search.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_secure.png new file mode 100644 index 000000000..d49217234 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_secure.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_select_all.png new file mode 100644 index 000000000..da37d7a6e Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_select_all.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_save.png new file mode 100644 index 000000000..29c5f4d3b Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_save.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_search.png new file mode 100644 index 000000000..aad535e97 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_search.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_secure.png new file mode 100644 index 000000000..2a0898381 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_secure.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_select_all.png new file mode 100644 index 000000000..af37a3680 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xhdpi/ic_action_select_all.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_save.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_save.png new file mode 100644 index 000000000..744350049 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_save.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_search.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_search.png new file mode 100644 index 000000000..9c0ea3ca0 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_search.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_secure.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_secure.png new file mode 100644 index 000000000..d8c094ed8 Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_secure.png differ diff --git a/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_select_all.png b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_select_all.png new file mode 100644 index 000000000..aa5937eab Binary files /dev/null and b/OpenPGP-Keychain/src/main/res/drawable-xxhdpi/ic_action_select_all.png differ diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_error_message.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_error_message.xml index 5927dbf43..48aa89d4f 100644 --- a/OpenPGP-Keychain/src/main/res/layout/api_app_error_message.xml +++ b/OpenPGP-Keychain/src/main/res/layout/api_app_error_message.xml @@ -1,6 +1,5 @@ diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_select_pub_keys_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_select_pub_keys_activity.xml index 877b4e74e..a10592607 100644 --- a/OpenPGP-Keychain/src/main/res/layout/api_app_select_pub_keys_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/api_app_select_pub_keys_activity.xml @@ -1,6 +1,5 @@ diff --git a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml index e6c81c3fc..c56ba130e 100644 --- a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml @@ -71,7 +71,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" - android:text="Main User Id" + android:text="@string/label_main_user_id" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_alignTop="@+id/linearLayout" android:layout_toRightOf="@+id/relativeLayout" /> diff --git a/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml b/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml index 18210afc5..81ceba20c 100644 --- a/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml +++ b/OpenPGP-Keychain/src/main/res/layout/drawer_list.xml @@ -12,7 +12,7 @@ android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" - android:background="#fff" + android:background="@color/white" android:choiceMode="singleChoice" android:divider="@color/bg_gray" android:dividerHeight="1dp" /> diff --git a/OpenPGP-Keychain/src/main/res/layout/edit_key_activity.xml b/OpenPGP-Keychain/src/main/res/layout/edit_key_activity.xml index 182540dc5..fc4422cf0 100644 --- a/OpenPGP-Keychain/src/main/res/layout/edit_key_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/edit_key_activity.xml @@ -27,7 +27,7 @@ android:text="@string/label_no_passphrase" /> + android:text="@string/label_name" /> diff --git a/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml b/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml index 663949d8e..3030d6bae 100644 --- a/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml +++ b/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml @@ -49,7 +49,7 @@ android:paddingRight="5dip" android:text="@string/label_email" /> - @@ -82,7 +83,7 @@ android:layout_gravity="right" android:ellipsize="end" android:singleLine="true" - android:text="Sign User Id" + android:text="@string/label_sign_user_id" android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -135,7 +136,7 @@ @@ -153,7 +154,7 @@ @@ -251,51 +252,97 @@ - + android:orientation="horizontal" + android:clickable="true"> + - - + android:text="@string/btn_encryption_advanced_settings_show" + android:paddingTop="@dimen/padding_medium" + android:paddingBottom="@dimen/padding_medium" + android:textColor="@color/emphasis"/> + android:orientation="vertical" + android:visibility="gone"> - - + android:orientation="horizontal"> - + - + + + + android:orientation="horizontal"> + + + + + + + + + + + + + diff --git a/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml b/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml index 37d1c5702..3cc0bc6dc 100644 --- a/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml +++ b/OpenPGP-Keychain/src/main/res/layout/import_keys_list_entry.xml @@ -48,7 +48,7 @@ android:id="@+id/mainUserId" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Main User ID" + android:text="@string/label_main_user_id" android:textAppearance="?android:attr/textAppearanceMedium" /> - - + android:orientation="vertical"> + + android:visibility="gone" + android:gravity="center"> + + - - + android:paddingTop="4dip" + android:singleLine="true" /> - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml b/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml index 12c6b6caa..f52693138 100644 --- a/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml +++ b/OpenPGP-Keychain/src/main/res/layout/key_list_item.xml @@ -15,7 +15,7 @@ android:id="@+id/mainUserId" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Main User ID" + android:text="@string/label_main_user_id" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" diff --git a/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml b/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml index c162a6e28..6031bf7c7 100644 --- a/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml +++ b/OpenPGP-Keychain/src/main/res/layout/key_server_export.xml @@ -1,7 +1,6 @@ diff --git a/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml b/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml index 2bdd231ee..ae523762c 100644 --- a/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml +++ b/OpenPGP-Keychain/src/main/res/layout/passphrase_repeat_dialog.xml @@ -6,7 +6,9 @@ android:paddingRight="16dp" android:stretchColumns="1" > - + - + + android:orientation="horizontal"> + android:paddingLeft="4dp"> - + android:visibility="gone" + android:layout_marginRight="5dip" + android:text="" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml index c44835bb0..9e4bc70eb 100644 --- a/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_keys_item.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingRight="5dip" - android:text="Key ID" + android:text="@string/label_key_id" android:textAppearance="?android:attr/textAppearanceMedium" android:typeface="monospace" /> diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml index 644548183..6ef3f3072 100644 --- a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml @@ -92,7 +92,7 @@ android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" - android:stretchColumns="1"> + android:shrinkColumns="1"> diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml index 508d080a6..22f0cdc5f 100644 --- a/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml +++ b/OpenPGP-Keychain/src/main/res/layout/view_key_userids_item.xml @@ -10,7 +10,7 @@ android:id="@+id/userId" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="User ID" + android:text="@string/user_id" android:textAppearance="?android:attr/textAppearanceSmall" /> \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list.xml b/OpenPGP-Keychain/src/main/res/menu/key_list.xml index 23ab8c9f3..addef0c2d 100644 --- a/OpenPGP-Keychain/src/main/res/menu/key_list.xml +++ b/OpenPGP-Keychain/src/main/res/menu/key_list.xml @@ -4,12 +4,17 @@ - - \ No newline at end of file + + diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list_multi.xml b/OpenPGP-Keychain/src/main/res/menu/key_list_multi.xml index bbed11f07..db709052f 100644 --- a/OpenPGP-Keychain/src/main/res/menu/key_list_multi.xml +++ b/OpenPGP-Keychain/src/main/res/menu/key_list_multi.xml @@ -1,12 +1,21 @@ + + - \ No newline at end of file + diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_about.html b/OpenPGP-Keychain/src/main/res/raw-de/help_about.html index 50220bd0b..37d4193f7 100644 --- a/OpenPGP-Keychain/src/main/res/raw-de/help_about.html +++ b/OpenPGP-Keychain/src/main/res/raw-de/help_about.html @@ -2,7 +2,7 @@

http://www.openkeychain.org

-

OpenKeychain is an OpenPGP implementation for Android.

+

OpenKeychain ist eine OpenPGP implementation für Android.

Lizenz: GPLv3+

Entwickler OpenKeychain

diff --git a/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html index ea31d1f3d..1197869b5 100644 --- a/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html +++ b/OpenPGP-Keychain/src/main/res/raw-de/help_changelog.html @@ -86,7 +86,7 @@

1.0.2

    -
  • filterable key lists
  • +
  • Filterbare Schlüsselliste
  • smarter pre-selection of encryption keys
  • new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers
  • fixes and additional features (key preselection) for K-9 Mail, new beta build available
  • diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_about.html b/OpenPGP-Keychain/src/main/res/raw-el/help_about.html new file mode 100644 index 000000000..863aeee58 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-el/help_about.html @@ -0,0 +1,45 @@ + + + +

    http://www.openkeychain.org

    +

    OpenKeychain is an OpenPGP implementation for Android.

    +

    License: GPLv3+

    + +

    Developers OpenKeychain

    +
      +
    • Dominik Schürmann (Lead developer)
    • +
    • Ash Hughes (crypto patches)
    • +
    • Brian C. Barnes
    • +
    • Bahtiar 'kalkin' Gadimov (UI)
    • + +
    +

    Developers APG 1.x

    +
      +
    • 'Thialfihar' (Lead developer)
    • +
    • 'Senecaso' (QRCode, sign key, upload key)
    • +
    • Oliver Runge
    • +
    • Markus Doits
    • +
    +

    Libraries

    + + + diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-el/help_changelog.html new file mode 100644 index 000000000..abf660ba8 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-el/help_changelog.html @@ -0,0 +1,108 @@ + + + +

    2.3

    +
      +
    • remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)
    • +
    • fix setting expiry dates on keys (thanks to Ash Hughes)
    • +
    • more internal fixes when editing keys (thanks to Ash Hughes)
    • +
    • querying keyservers directly from the import screen
    • +
    • fix layout and dialog style on Android 2.2-3.0
    • +
    • fix crash on keys with empty user ids
    • +
    • fix crash and empty lists when coming back from signing screen
    • +
    • Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source
    • +
    • fix upload of key from signing screen
    • +
    +

    2.2

    +
      +
    • new design with navigation drawer
    • +
    • new public key list design
    • +
    • new public key view
    • +
    • bug fixes for importing of keys
    • +
    • key cross-certification (thanks to Ash Hughes)
    • +
    • handle UTF-8 passwords properly (thanks to Ash Hughes)
    • +
    • first version with new languages (thanks to the contributors on Transifex)
    • +
    • sharing of keys via QR Codes fixed and improved
    • +
    • package signature verification for API
    • +
    +

    2.1.1

    +
      +
    • API Updates, preparation for K-9 Mail integration
    • +
    +

    2.1

    +
      +
    • lots of bug fixes
    • +
    • new API for developers
    • +
    • PRNG bug fix by Google
    • +
    +

    2.0

    +
      +
    • complete redesign
    • +
    • share public keys via qr codes, nfc beam
    • +
    • sign keys
    • +
    • upload keys to server
    • +
    • fixes import issues
    • +
    • new AIDL API
    • +
    +

    1.0.8

    +
      +
    • basic keyserver support
    • +
    • app2sd
    • +
    • more choices for pass phrase cache: 1, 2, 4, 8, hours
    • +
    • translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)
    • +
    • bugfixes
    • +
    • optimizations
    • +
    +

    1.0.7

    +
      +
    • fixed problem with signature verification of texts with trailing newline
    • +
    • more options for pass phrase cache time to live (20, 40, 60 mins)
    • +
    +

    1.0.6

    +
      +
    • account adding crash on Froyo fixed
    • +
    • secure file deletion
    • +
    • option to delete key file after import
    • +
    • stream encryption/decryption (gallery, etc.)
    • +
    • new options (language, force v3 signatures)
    • +
    • interface changes
    • +
    • bugfixes
    • +
    +

    1.0.5

    +
      +
    • German and Italian translation
    • +
    • much smaller package, due to reduced BC sources
    • +
    • new preferences GUI
    • +
    • layout adjustment for localization
    • +
    • signature bugfix
    • +
    +

    1.0.4

    +
      +
    • fixed another crash caused by some SDK bug with query builder
    • +
    +

    1.0.3

    +
      +
    • fixed crashes during encryption/signing and possibly key export
    • +
    +

    1.0.2

    +
      +
    • filterable key lists
    • +
    • smarter pre-selection of encryption keys
    • +
    • new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers
    • +
    • fixes and additional features (key preselection) for K-9 Mail, new beta build available
    • +
    +

    1.0.1

    +
      +
    • GMail account listing was broken in 1.0.0, fixed again
    • +
    +

    1.0.0

    +
      +
    • K-9 Mail integration, APG supporting beta build of K-9 Mail
    • +
    • support of more file managers (including ASTRO)
    • +
    • Slovenian translation
    • +
    • new database, much faster, less memory usage
    • +
    • defined Intents and content provider for other apps
    • +
    • bugfixes
    • +
    + + diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-el/help_nfc_beam.html new file mode 100644 index 000000000..88492731c --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-el/help_nfc_beam.html @@ -0,0 +1,12 @@ + + + +

    How to receive keys

    +
      +
    1. Go to your partners contacts and open the contact you want to share.
    2. +
    3. Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.
    4. +
    5. After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.
    6. +
    7. Tap the card and the content will then load on the your device.
    8. +
    + + diff --git a/OpenPGP-Keychain/src/main/res/raw-el/help_start.html b/OpenPGP-Keychain/src/main/res/raw-el/help_start.html new file mode 100644 index 000000000..3a6443a2f --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-el/help_start.html @@ -0,0 +1,19 @@ + + + +

    Getting started

    +

    First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.

    + +

    It is recommended that you install OI File Manager for enhanced file selection and Barcode Scanner to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.

    + +

    I found a bug in OpenKeychain!

    +

    Please report the bug using the issue tracker of OpenKeychain.

    + +

    Contribute

    +

    If you want to help us developing OpenKeychain by contributing code follow our small guide on Github.

    + +

    Translations

    +

    Help translating OpenKeychain! Everybody can participate at OpenKeychain on Transifex.

    + + + diff --git a/OpenPGP-Keychain/src/main/res/raw-el/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-el/nfc_beam_share.html new file mode 100644 index 000000000..083e055c7 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-el/nfc_beam_share.html @@ -0,0 +1,11 @@ + + + +
      +
    1. Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.
    2. +
    3. Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.
    4. +
    5. After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.
    6. +
    7. Tap the card and the content will then load on the other person’s device.
    8. +
    + + diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_about.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_about.html new file mode 100644 index 000000000..863aeee58 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_about.html @@ -0,0 +1,45 @@ + + + +

    http://www.openkeychain.org

    +

    OpenKeychain is an OpenPGP implementation for Android.

    +

    License: GPLv3+

    + +

    Developers OpenKeychain

    +
      +
    • Dominik Schürmann (Lead developer)
    • +
    • Ash Hughes (crypto patches)
    • +
    • Brian C. Barnes
    • +
    • Bahtiar 'kalkin' Gadimov (UI)
    • + +
    +

    Developers APG 1.x

    +
      +
    • 'Thialfihar' (Lead developer)
    • +
    • 'Senecaso' (QRCode, sign key, upload key)
    • +
    • Oliver Runge
    • +
    • Markus Doits
    • +
    +

    Libraries

    + + + diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_changelog.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_changelog.html new file mode 100644 index 000000000..abf660ba8 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_changelog.html @@ -0,0 +1,108 @@ + + + +

    2.3

    +
      +
    • remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)
    • +
    • fix setting expiry dates on keys (thanks to Ash Hughes)
    • +
    • more internal fixes when editing keys (thanks to Ash Hughes)
    • +
    • querying keyservers directly from the import screen
    • +
    • fix layout and dialog style on Android 2.2-3.0
    • +
    • fix crash on keys with empty user ids
    • +
    • fix crash and empty lists when coming back from signing screen
    • +
    • Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source
    • +
    • fix upload of key from signing screen
    • +
    +

    2.2

    +
      +
    • new design with navigation drawer
    • +
    • new public key list design
    • +
    • new public key view
    • +
    • bug fixes for importing of keys
    • +
    • key cross-certification (thanks to Ash Hughes)
    • +
    • handle UTF-8 passwords properly (thanks to Ash Hughes)
    • +
    • first version with new languages (thanks to the contributors on Transifex)
    • +
    • sharing of keys via QR Codes fixed and improved
    • +
    • package signature verification for API
    • +
    +

    2.1.1

    +
      +
    • API Updates, preparation for K-9 Mail integration
    • +
    +

    2.1

    +
      +
    • lots of bug fixes
    • +
    • new API for developers
    • +
    • PRNG bug fix by Google
    • +
    +

    2.0

    +
      +
    • complete redesign
    • +
    • share public keys via qr codes, nfc beam
    • +
    • sign keys
    • +
    • upload keys to server
    • +
    • fixes import issues
    • +
    • new AIDL API
    • +
    +

    1.0.8

    +
      +
    • basic keyserver support
    • +
    • app2sd
    • +
    • more choices for pass phrase cache: 1, 2, 4, 8, hours
    • +
    • translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)
    • +
    • bugfixes
    • +
    • optimizations
    • +
    +

    1.0.7

    +
      +
    • fixed problem with signature verification of texts with trailing newline
    • +
    • more options for pass phrase cache time to live (20, 40, 60 mins)
    • +
    +

    1.0.6

    +
      +
    • account adding crash on Froyo fixed
    • +
    • secure file deletion
    • +
    • option to delete key file after import
    • +
    • stream encryption/decryption (gallery, etc.)
    • +
    • new options (language, force v3 signatures)
    • +
    • interface changes
    • +
    • bugfixes
    • +
    +

    1.0.5

    +
      +
    • German and Italian translation
    • +
    • much smaller package, due to reduced BC sources
    • +
    • new preferences GUI
    • +
    • layout adjustment for localization
    • +
    • signature bugfix
    • +
    +

    1.0.4

    +
      +
    • fixed another crash caused by some SDK bug with query builder
    • +
    +

    1.0.3

    +
      +
    • fixed crashes during encryption/signing and possibly key export
    • +
    +

    1.0.2

    +
      +
    • filterable key lists
    • +
    • smarter pre-selection of encryption keys
    • +
    • new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers
    • +
    • fixes and additional features (key preselection) for K-9 Mail, new beta build available
    • +
    +

    1.0.1

    +
      +
    • GMail account listing was broken in 1.0.0, fixed again
    • +
    +

    1.0.0

    +
      +
    • K-9 Mail integration, APG supporting beta build of K-9 Mail
    • +
    • support of more file managers (including ASTRO)
    • +
    • Slovenian translation
    • +
    • new database, much faster, less memory usage
    • +
    • defined Intents and content provider for other apps
    • +
    • bugfixes
    • +
    + + diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_nfc_beam.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_nfc_beam.html new file mode 100644 index 000000000..88492731c --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_nfc_beam.html @@ -0,0 +1,12 @@ + + + +

    How to receive keys

    +
      +
    1. Go to your partners contacts and open the contact you want to share.
    2. +
    3. Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.
    4. +
    5. After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.
    6. +
    7. Tap the card and the content will then load on the your device.
    8. +
    + + diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_start.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_start.html new file mode 100644 index 000000000..f8c255232 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/help_start.html @@ -0,0 +1,19 @@ + + + +

    شروع کار

    +

    اول شما نیاز به یک جفت کلید شخصی دارید. از طریق منوها در "کلیدهای من" بسازید و یا از طریق"واردات کلیدهای" جفت کلیدهای موجود را وارد کنید. پس از آن، شما می توانید کلید های دوستان خود را دانلود کنید و یا آنها را از طریق کدهای QR یا NFC رد و بدل کنید.

    + +

    It is recommended that you install OI File Manager for enhanced file selection and Barcode Scanner to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.

    + +

    I found a bug in OpenKeychain!

    +

    Please report the bug using the issue tracker of OpenKeychain.

    + +

    هم بخشی کردن

    +

    If you want to help us developing OpenKeychain by contributing code follow our small guide on Github.

    + +

    ترجمه ها

    +

    Help translating OpenKeychain! Everybody can participate at OpenKeychain on Transifex.

    + + + diff --git a/OpenPGP-Keychain/src/main/res/raw-fa-rIR/nfc_beam_share.html b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/nfc_beam_share.html new file mode 100644 index 000000000..083e055c7 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/raw-fa-rIR/nfc_beam_share.html @@ -0,0 +1,11 @@ + + + +
      +
    1. Make sure that NFC is turned on in Settings > More > NFC and make sure that Android Beam is also on in the same section.
    2. +
    3. Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.
    4. +
    5. After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.
    6. +
    7. Tap the card and the content will then load on the other person’s device.
    8. +
    + + diff --git a/OpenPGP-Keychain/src/main/res/values-de/strings.xml b/OpenPGP-Keychain/src/main/res/values-de/strings.xml index 09b4fdb23..dcb21dea3 100644 --- a/OpenPGP-Keychain/src/main/res/values-de/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-de/strings.xml @@ -13,7 +13,6 @@ Einstellungen Registrierte Anwendungen Schlüsselserver - Passwort ändern Passwort setzen E-Mail senden... In eine Datei verschlüsseln @@ -266,12 +265,14 @@ Ablaufdatum muss später sein als das Erstellungsdatum Sie können diesen Kontakt nicht löschen, denn es ist ihr eigener. Sie können folgende Kontakte nicht löschen, denn sie gehören Ihnen selbst:\n%s + Keyserveranfrage fehlgeschlagen Bitte lösche ihn unter \'Meine Schlüssel\'! Bitte lösche sie unter \'Meine Schlüssel\'! fertig. + Abbrechen speichern... importieren... exportieren... @@ -337,10 +338,6 @@ Hilfe Füge den Schlüssel aus der Zwischenablage ein - OpenKeychain: Datei entschlüsseln - OpenKeychain: Schlüssel importieren - OpenKeychain: Verschlüsseln - OpenKeychain: Entschlüsseln Keine registrierten Anwendungen vorhanden!\n\nAnwendungen von Dritten können Zugriff auf OpenKeychain erbitten. Nachdem Zugriff gewährt wurde, werden diese hier aufgelistet. Erweiterte Einstellungen anzeigen diff --git a/OpenPGP-Keychain/src/main/res/values-el/strings.xml b/OpenPGP-Keychain/src/main/res/values-el/strings.xml new file mode 100644 index 000000000..84b39c221 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/values-el/strings.xml @@ -0,0 +1,53 @@ + + + + Επιλογή Δημόσιου Κλειδιού + Επιλογή Ιδιωτικού Κλειδιού + Κωδικός + Δημιουργία Κλειδιού + Επεξεργασία Κλειδιού + Επιλογές + + + Υπόγραψε + Αποθήκευση + Ακύρωση + Διαγραφή + Κανένα + ΟΚ + Αλλαγή κωδικού + Επέλεξε Κωδικό + + Διαγραφής κλειδιού + Δημιουργίας κλειδιού + + Υπόγραψε + Μήνυμα + Αρχείο + Κωδικός + Ξανά + Αλγόριθμος + Αλγόριθμος κρυπτογράφησης + Δημόσιο κλειδί + Κωδικός + Μέγεθος κλειδιού + Ηλεκτρονικό ταχυδρομίο + + + + + + + + + + + + + + + + + diff --git a/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml b/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml index 6efe9548d..41dc629aa 100644 --- a/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-es-rCO/strings.xml @@ -10,7 +10,6 @@ Editar clave Preferencias Aplicaciones registradas - Cambiar contraseña Establecer contraseña Enviar correo electrónico... Cifrar a archivo diff --git a/OpenPGP-Keychain/src/main/res/values-es/strings.xml b/OpenPGP-Keychain/src/main/res/values-es/strings.xml index 48ea6cc69..c643a3cd8 100644 --- a/OpenPGP-Keychain/src/main/res/values-es/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-es/strings.xml @@ -13,7 +13,7 @@ Preferencias Aplicaciones registradas Prioridad del servidor de claves - Cambiar la frase de contraseña + Cambiar frase de contraseña Establecer frase de contraseña Enviar email... Cifrar hacia archivo @@ -92,6 +92,7 @@ Ajustes de Beam Cancelar Cifrar hacia... + Seleccionar todo Firmar Mensaje @@ -125,6 +126,7 @@ Cargar clave al servidor de claves seleccionado después de la certificación Huella digital Seleccionar + Establer la fecha de vencimiento %d seleccionado %d seleccionados @@ -266,12 +268,16 @@ la fecha de caducidad debe ser posterior a la fecha de creación no puedes eliminar este contacto porque eres tú mismo. no puedes eliminar los siguientes contactos porque son tú mismo:\n%s + Consulta al servidor insuficiente + La consulta al servidor de claves ha fallado + Demasiadas respuestas Por favor, bórralo desde la pantalla \'Mis claves\'! Por favor, bórralos desde la pantalla \'Mis claves\'! hecho. + cancelar guardando... importando... exportando... @@ -337,10 +343,10 @@ Ayuda Tomar la clave desde el portapapeles - OpenKeychain: Descifrar archivo - OpenKeychain: Importar clave - OpenKeychain: Cifrar - OpenKeychain: Descifrar + Descifrar archivo con OpenKeychain + Importar clave con OpenKeychain + Cifrar con OpenKeychain + Descifrar con OpenKeychain ¡No hay aplicaciones registradas!\n\nLas aplicaciones de terceros pueden pedir permiso de acceso a OpenKeychain. Después de obtener acceso, serán enumeradas aquí. Mostrar la configuración avanzada diff --git a/OpenPGP-Keychain/src/main/res/values-fa-rIR/strings.xml b/OpenPGP-Keychain/src/main/res/values-fa-rIR/strings.xml new file mode 100644 index 000000000..6bb115049 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/values-fa-rIR/strings.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenPGP-Keychain/src/main/res/values-fr/strings.xml b/OpenPGP-Keychain/src/main/res/values-fr/strings.xml index bf66756cf..d99bbcd7c 100644 --- a/OpenPGP-Keychain/src/main/res/values-fr/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-fr/strings.xml @@ -13,9 +13,10 @@ Préférences Applications enregistrées Préférences du serveur de clefs - Changer la phrase de passe + Modifier la phrase de passe Définir la phrase de passe Envoyer un courriel... + Envoyer un fichier... Chiffrer vers un fichier Déchiffrer vers un fichier importer des clefs @@ -92,6 +93,7 @@ Paramètres Beam Annuler Chiffrer vers... + Tout sélectionner Signer Message @@ -104,6 +106,7 @@ Destinataires Supprimer après le chiffrement Supprimer après le chiffrement + Partager après chiffrement Algorithme de chiffrement Algorithme de hachage Clef publique @@ -122,9 +125,12 @@ Nom Commentaire Courriel + Signer l\'ID utilisateur + Signer le courriel Téléverser la clef vers le serveur de clefs choisi après certification Empreinte Choisir + Définir une date d\'expiration %d choisie %d choisies @@ -137,6 +143,7 @@ peut signer expiré révoquée + ID utilisateur %d serveur de clefs %d serveurs de clefs @@ -269,12 +276,19 @@ Requête serveur insuffisante Échec lors de l\'interrogation du serveur de clefs Trop de réponses + Le fichier n\'a pas de contenu + Une erreur générique est survenue, veuillez créer un nouveau rapport de bogue pour OpenKeychain. Veuillez le supprimer depuis l\'écran « Mes Clefs »! Veuillez les supprimer depuis l\'écran « Mes Clefs »! + + une partie du fichier chargé est un objet OpenPGP valide mais pas une clef OpenPGP + certaines parties du fichier chargé sont des objets OpenPGP valides mais pas des clefs OpenPGP + fait. + annuler sauvegarde... importation... exportation... @@ -340,10 +354,10 @@ Aide Obtenir la clef depuis le presse-papiers - OpenKeychain : déchiffrer le ficher - OpenKeychain : importer la clef - OpenKeychain : chiffrer - OpenKeychain : déchiffrer + Déchiffrer le fichier avec OpenKeychain + Importer la clef avec OpenKeychain + Chiffrer avec OpenKeychain + Déchiffrer avec OpenKeychain Aucune application enregistrée !\n\nLes applications tierces peuvent demander l\'accès à OpenKeychain. Après avoir autorisé l\'accès, elles seront listées ici. Afficher les paramètres avancés diff --git a/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml b/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml index 86a094c41..f9e7074da 100644 --- a/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-it-rIT/strings.xml @@ -13,9 +13,10 @@ Preferenze App Registrate Preferenze Server delle Chiavi - Cambia Frase di Accesso + Cambia Frase Di Accesso Imposta Frase di Accesso Invia Mail... + Invia file... Codifica File Decodifica File Importa Chiavi @@ -92,6 +93,7 @@ Impostazioni Beam Annulla Codifica su... + Seleziona tutto Firma Messaggio @@ -104,6 +106,7 @@ Destinatari Cancella Dopo Codifica Cancella Dopo Decodifica + Condividi Dopo la Codifica Algoritmo di Codifica Algoritmo di Hash Chiave Pubblica @@ -122,9 +125,12 @@ Nome Commento Email + Firma ID Utente + Firma email Carica chiave nel server delle chiavi selezionati dopo la certificazione Impronta Seleziona + Impostare la data di scadenza %d selezionato %d selezionati @@ -137,6 +143,7 @@ puo\' firmare scaduto revocato + ID Utente %d server delle chiavi %d server delle chiavi @@ -269,12 +276,19 @@ Query di server insufficiente Interrogazione del server delle chiavi fallita Troppi responsi + Il File non ha contenuti + Si è verificato un errore generico, si prega di creare una nuova segnalazione di errore per OpenKeychain. Per favore cancellala dalla schermata \'Mie Chavi\' Per favore cancellatele dalla schermata \'Mie Chavi\' + + parte del file caricato e\' un oggetto OpenPGP valido, ma non una chave OpenPGP + parti del file caricato sono oggetti OpenPGP validi, ma non chavi OpenPGP + fatto. + cancella salvataggio... importazione... esportazione... @@ -340,10 +354,10 @@ Aiuto Ottieni chiave dagli appunti - OpenKeyChain: Decodifica File - OpenKeyChain: Importa Chiave - OpenKeychain: Codifica - OpenKeychain: Decodifica + Decodifica File con OpenKeychain + Importa Chiave con OpenKeychain + Codifica con OpenKeychain + Decodifica con OpenKeychain Nessuna app registrata!\n\nApp di terza parti possono richiedere accesso a OpenKeychain. Dopo aver concesso l\'accesso, saranno elencate qui. Mostra impostazioni avanzate diff --git a/OpenPGP-Keychain/src/main/res/values-ja/strings.xml b/OpenPGP-Keychain/src/main/res/values-ja/strings.xml index c99f8b31c..e5ee5ecc0 100644 --- a/OpenPGP-Keychain/src/main/res/values-ja/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-ja/strings.xml @@ -13,9 +13,10 @@ 設定 登録済みのアプリケーション 鍵サーバ設定 - パスフレーズの変更 + パスフレーズの変更 パスフレーズの設定 メールの送信... + ファイルの送信... 暗号化してファイルに 復号化してファイルに 鍵のインポート @@ -92,6 +93,7 @@ Beamの設定 キャンセル 暗号化... + すべて選択 署名 メッセージ @@ -104,6 +106,7 @@ 受信者 暗号化後に削除 復号化後に削除 + 暗号化して共有 暗号化アルゴリズム ハッシュアルゴリズム 公開鍵 @@ -122,9 +125,12 @@ 名前 コメント Eメールアドレス + 署名ユーザーID + メールを署名 証明後選択した鍵サーバに鍵をアップロード 指紋 選択 + 期限日時を設定 %d を選択 @@ -136,6 +142,7 @@ 署名可能 期限切れ 破棄 + ユーザーID %d の鍵サーバ @@ -261,11 +268,17 @@ サーバへのクエリーが不足しています 鍵サーバへのクエリーが失敗 レスポンスが多すぎます + ファイルに内容がありません + 一般エラーが発生しました、この新しいバグの情報をOpenKeychainプロジェクトに送ってください \'自分の鍵\'画面から削除してください! + + 読み込んだファイルのOpenPGPオブジェクト部分は正しいですが、OpenPGPの鍵ではありません + 完了。 + キャンセル 保存... インポート... エクスポート... @@ -329,10 +342,10 @@ ヘルプ クリップボードから鍵を取得 - OpenKeychain: ファイル復号化 - OpenKeychain: 鍵のインポート - OpenKeychain: 暗号化 - OpenKeychain: 復号化 + OpenKeychainでファイルを復号化 + OpenKeychainに鍵をインポート + OpenKeychainで暗号化 + OpenKeychainで復号化 登録されていないアプリケーション!\n\nサードパーティアプリケーションはOpenKeychainにアクセスを要求できます。アクセスを与えた後、それらはここにリストされます。 拡張設定を表示 diff --git a/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml b/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml index 7d7efa616..de6ba554d 100644 --- a/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-nl-rNL/strings.xml @@ -10,7 +10,6 @@ Sleutel bewerken Instellingen Geregistreerde apps - Wachtwoord wijzigen Wachtwoord instellen E-mail verzenden... Versleutelen naar bestand diff --git a/OpenPGP-Keychain/src/main/res/values-ru/strings.xml b/OpenPGP-Keychain/src/main/res/values-ru/strings.xml index 7d865cc23..22f676ccb 100644 --- a/OpenPGP-Keychain/src/main/res/values-ru/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-ru/strings.xml @@ -13,7 +13,7 @@ Настройки Связанные приложения Настройки сервера ключей - Изменить пароль + Изменить пароль Задать пароль Отправить... Зашифровать в файл @@ -92,6 +92,7 @@ Настройки Beam Отмена Зашифровать.... + Выбрать все Подписать Сообщение @@ -125,6 +126,7 @@ После сертификации загрузить ключ на сервер Отпечаток Выбрать + Срок годности %d выбран %d выбрано @@ -284,6 +286,7 @@ готово. + отмена сохранение... импорт... экспорт... diff --git a/OpenPGP-Keychain/src/main/res/values-uk/strings.xml b/OpenPGP-Keychain/src/main/res/values-uk/strings.xml index 7f1766a5c..7ccb661d3 100644 --- a/OpenPGP-Keychain/src/main/res/values-uk/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-uk/strings.xml @@ -13,9 +13,10 @@ Налаштування Зареєстровані програми Налаштування сервера ключів - Змінити парольну фразу + Змінити парольну фразу Задати парольну фразу Надіслати листа… + Надіслати файл… Зашифрувати до файлу Розшифрувати до файлу Імпортувати ключі @@ -92,6 +93,7 @@ Налаштування променя Скасувати Зашифрувати… + Вибрати усе Підпис Повідомлення @@ -104,6 +106,7 @@ Отримувачі Вилучити після шифрування Вилучити після розшифрування + Поширити після шифрування Алгоритм шифрування Хеш алгоритм Публічний ключ @@ -122,9 +125,12 @@ Назва Коментар Ел. пошта + Ід підпису користувача + Підписати листа Завантажити ключ до вибраного сервера ключів після сертифікації Відбиток Вибрати + Задати термін дії %d вибраний %d вибрані @@ -138,6 +144,7 @@ можна підписати закінчився скасовано + ІД користувача %d сервер ключів %d сервери ключів @@ -277,13 +284,21 @@ Запит обмеженого сервера Збій сервера ключа запиту Забагато відповідей + Файл не має вмісту + Трапилася загальна помилка, будь ласка, створіть новий звіт про помилку для OpenKeychain. Будь ласка, вилучіть його з екрану „Мої ключі“! Будь ласка, вилучіть їх з екрану „Мої ключі“! Будь ласка, вилучіть їх з екрану „Мої ключі“! + + частина завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP + частини завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP + частин завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP + готово. + cкасувати збереження… імпортується… експортується… @@ -351,10 +366,10 @@ Довідка Отримати ключ з буфера обміну - OpenPGP: розшифрувати файл - OpenPGP: імпортувати ключ - OpenPGP: зашифрувати - OpenPGP: розшифрувати + Розшифрувати файл з OpenKeychain + Імпортувати ключ з OpenKeychain + Зашифрувати з OpenKeychain + Розшифрувати з OpenKeychain Нема зареєстрованих програм!\n\nСтороні програми можуть вимагати доступ до OpenPGP Keychain. Після надання доступу вони будуть наведені тут. Показати додаткові налаштування diff --git a/OpenPGP-Keychain/src/main/res/values-zh/strings.xml b/OpenPGP-Keychain/src/main/res/values-zh/strings.xml index f9422b64b..80413d589 100644 --- a/OpenPGP-Keychain/src/main/res/values-zh/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values-zh/strings.xml @@ -1,17 +1,47 @@ + 选择公钥 + 选择私钥 加密 解密 + 密码短语 + 创建密钥 + 编辑密钥 + 参数 + 已注册应用 密钥服务器偏好 + 设置密码短语 + 发送邮件 + 加密至文件 + 解密至文件 + 导入密钥 + 导出密钥 + 导出密钥 + 无法找到密钥 查询密钥服务器 上传到密钥服务器 + 未知签名密钥 + 帮助 + 用户ID + 密钥 + 常规 + 缺省 + 高级 主密钥 密钥服务器 解密并验证 + 签名 + 解密 解密并验证 + 选择收件人 + 加密文件 + 保存 + 取消 + 删除 + 剪贴板 帮助 diff --git a/OpenPGP-Keychain/src/main/res/values/arrays.xml b/OpenPGP-Keychain/src/main/res/values/arrays.xml index 974239110..5244de419 100644 --- a/OpenPGP-Keychain/src/main/res/values/arrays.xml +++ b/OpenPGP-Keychain/src/main/res/values/arrays.xml @@ -1,7 +1,7 @@ - + @string/choice_15secs @string/choice_1min @string/choice_3mins @@ -15,7 +15,7 @@ @string/choice_8hours @string/choice_forever - + 15 60 180 diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml index 723661928..d2e02efcb 100644 --- a/OpenPGP-Keychain/src/main/res/values/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values/strings.xml @@ -14,9 +14,10 @@ Preferences Registered Applications Keyserver Preference - Change Passphrase + Change Passphrase Set Passphrase "Send Mail…" + "Send File…" Encrypt To File Decrypt To File Import Keys @@ -66,6 +67,8 @@ Clipboard Share with… Lookup key + Show advanced settings + Hide advanced settings Settings @@ -96,6 +99,7 @@ Beam settings Cancel Encrypt to… + Select all Sign @@ -109,6 +113,7 @@ Recipients Delete After Encryption Delete After Decryption + Share After Encryption Encryption Algorithm Hash Algorithm Public Key @@ -127,9 +132,12 @@ Name Comment Email + Sign User Id + Sign email Upload key to selected keyserver after certification Fingerprint Select + Set expiry date %d selected @@ -139,11 +147,13 @@ <no name> <none> <no key> + <No Email> can encrypt can sign expired revoked + User ID 1 contact @@ -269,6 +279,7 @@ the master key cannot be an ElGamal key unknown algorithm choice you need to specify a name + no email found you need to specify an email address need at least one user id main user id must not be empty @@ -294,10 +305,16 @@ Insufficient server query Querying keyserver failed Too many responses + File has no content + A generic error occurred, please create a new bug report for OpenKeychain. Please delete it from the \'My Keys\' screen! Please delete them from the \'My Keys\' screen! + + part of the loaded file is a valid OpenPGP object but not a OpenPGP key + parts of the loaded file are valid OpenPGP objects but not OpenPGP keys + done. @@ -305,7 +322,6 @@ saving… importing… exporting… - generating key, this can take up to 3 minutes… building key… preparing master key… certifying master key… @@ -318,6 +334,11 @@ exporting keys… + + generating key, this can take up to 3 minutes… + generating keys, this can take up to 3 minutes… + + extracting signature key… extracting key… preparing streams… diff --git a/OpenPGP-Keychain/src/main/res/xml/preferences.xml b/OpenPGP-Keychain/src/main/res/xml/adv_preferences.xml similarity index 77% rename from OpenPGP-Keychain/src/main/res/xml/preferences.xml rename to OpenPGP-Keychain/src/main/res/xml/adv_preferences.xml index f5b46c232..2705bd22f 100644 --- a/OpenPGP-Keychain/src/main/res/xml/preferences.xml +++ b/OpenPGP-Keychain/src/main/res/xml/adv_preferences.xml @@ -15,21 +15,7 @@ limitations under the License. --> - - - - - - - + - \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/xml/gen_preferences.xml b/OpenPGP-Keychain/src/main/res/xml/gen_preferences.xml new file mode 100644 index 000000000..9f1883df0 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/xml/gen_preferences.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/xml/preference_headers.xml b/OpenPGP-Keychain/src/main/res/xml/preference_headers.xml new file mode 100644 index 000000000..3506ba322 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/xml/preference_headers.xml @@ -0,0 +1,25 @@ + + + + +
    +
    + \ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/res/xml/preference_headers_legacy.xml b/OpenPGP-Keychain/src/main/res/xml/preference_headers_legacy.xml new file mode 100644 index 000000000..141bf93e5 --- /dev/null +++ b/OpenPGP-Keychain/src/main/res/xml/preference_headers_legacy.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index ba13e901b..4b997c59f 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,9 @@ Development mailinglist at http://groups.google.com/d/forum/openpgp-keychain-dev 1. Have Android SDK "tools", "platform-tools", and "build-tools" directories in your PATH (http://developer.android.com/sdk/index.html) 2. Open the Android SDK Manager (shell command: ``android``). -Expand the Tools directory and select "Android SDK Build-tools" newest version. +Expand the Tools directory and select "Android SDK Build-tools (Version 19.0.3)". Expand the Extras directory and install "Android Support Repository" -Select everything for the newest SDK +Select everything for the newest SDK (API-Level 19) 3. Export ANDROID_HOME pointing to your Android SDK 4. Execute ``./gradlew build`` 5. You can install the app with ``adb install -r OpenPGP-Keychain/build/apk/OpenPGP-Keychain-debug-unaligned.apk`` @@ -116,6 +116,15 @@ When changing build files or dependencies, respect the following requirements: * No dependencies from Maven (also a soft requirement for inclusion in [F-Droid](https://f-droid.org)) * Always use a fixed Android Gradle plugin version not a dynamic one, e.g. ``0.7.3`` instead of ``0.7.+`` (allows offline builds without lookups for new versions, also some minor Android plugin versions had serious issues, i.e. [0.7.2 and 0.8.1](http://tools.android.com/tech-docs/new-build-system)) * Commit the corresponding [Gradle wrapper](http://www.gradle.org/docs/current/userguide/gradle_wrapper.html) to the repository (allows easy building for new contributors without the need to install the required Gradle version using a package manager) +* In order to update the build system to a newer gradle version you need to: + * Update every build.gradle file with the new gradle version and/or gradle plugin version + * build.gradle + * OpenPGP-Keychain/build.gradle + * OpenPGP-Keychain-API/build.gradle + * OpenPGP-Keychain-API/example-app/build.gradle + * OpenPGP-Keychain-API/libraries/keychain-api-library/build.gradle + * run ./gradlew wrapper twice to update gradle and download the new jar file + * commit the new jar and property files ### Translations @@ -146,6 +155,14 @@ See http://source.android.com/source/code-style.html See http://www.androidpolice.com/2009/11/04/auto-formatting-android-xml-files-with-eclipse/ +### Automated syntax check with CheckStyle +* Paste the tools/checkstyle.xml file to ~/.AndroidStudioPreview/config/codestyles/ (in Linux/Unix) + or ~/Library/Preferences/AndroidStudioPreview/codestyles (in Mac OSX) +* Go to Settings (or Preferences in Mac OS X) > Code Style > Java, select OpenPgpChecker, + as well as Code Style > XML and select OpenPgpChecker again. +* Start code inspection and see the results by selecting Analyze > Inspect Code from Android-Studio + or you can directly run checkstyle via cli with .tools/checkstyle. Make sure it's executable first. + ## Licenses OpenPGP Kechain is licensed under GPLv3+. Some parts (older parts and some libraries are Apache License v2, MIT X11 License) diff --git a/build.gradle b/build.gradle index 86c40fa3a..25651cd5a 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.8.3' + classpath 'com.android.tools.build:gradle:0.9.0' } } @@ -16,4 +16,4 @@ allprojects { task wrapper(type: Wrapper) { gradleVersion = '1.10' -} \ No newline at end of file +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9559bfd8b..d8e0b5b29 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Feb 09 18:34:27 CET 2014 +#Thu Mar 06 22:23:44 CET 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip diff --git a/libraries/Android-AppMsg/library/build.gradle b/libraries/Android-AppMsg/library/build.gradle index 934cf1cb1..f77f1a098 100644 --- a/libraries/Android-AppMsg/library/build.gradle +++ b/libraries/Android-AppMsg/library/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'android-library' android { compileSdkVersion 19 - buildToolsVersion '19.0.1' + buildToolsVersion '19.0.3' defaultConfig { minSdkVersion 4 diff --git a/libraries/AndroidBootstrap/build.gradle b/libraries/AndroidBootstrap/build.gradle index 7724c6d9c..220613132 100644 --- a/libraries/AndroidBootstrap/build.gradle +++ b/libraries/AndroidBootstrap/build.gradle @@ -2,10 +2,10 @@ apply plugin: 'android-library' android { compileSdkVersion 19 - buildToolsVersion "19.0.1" + buildToolsVersion "19.0.3" defaultConfig { minSdkVersion 7 - targetSdkVersion 17 + targetSdkVersion 19 } sourceSets { main { diff --git a/libraries/HtmlTextView/build.gradle b/libraries/HtmlTextView/build.gradle index a0b9b1bc6..d1b26d2bd 100644 --- a/libraries/HtmlTextView/build.gradle +++ b/libraries/HtmlTextView/build.gradle @@ -2,8 +2,8 @@ apply plugin: 'android-library' android { - compileSdkVersion 17 - buildToolsVersion '19.0.1' + compileSdkVersion 19 + buildToolsVersion '19.0.3' sourceSets { main { diff --git a/libraries/HtmlTextView/project.properties b/libraries/HtmlTextView/project.properties index 484dab075..91d2b0246 100644 --- a/libraries/HtmlTextView/project.properties +++ b/libraries/HtmlTextView/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-19 android.library=true diff --git a/libraries/StickyListHeaders/library/build.gradle b/libraries/StickyListHeaders/library/build.gradle index a92c4d80e..b67172c12 100644 --- a/libraries/StickyListHeaders/library/build.gradle +++ b/libraries/StickyListHeaders/library/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'android-library' android { compileSdkVersion 19 - buildToolsVersion '19.0.1' + buildToolsVersion '19.0.3' sourceSets { main { diff --git a/libraries/zxing-android-integration/build.gradle b/libraries/zxing-android-integration/build.gradle index a92c4d80e..b67172c12 100644 --- a/libraries/zxing-android-integration/build.gradle +++ b/libraries/zxing-android-integration/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'android-library' android { compileSdkVersion 19 - buildToolsVersion '19.0.1' + buildToolsVersion '19.0.3' sourceSets { main { diff --git a/libraries/zxing/build.gradle b/libraries/zxing/build.gradle index a92c4d80e..b67172c12 100644 --- a/libraries/zxing/build.gradle +++ b/libraries/zxing/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'android-library' android { compileSdkVersion 19 - buildToolsVersion '19.0.1' + buildToolsVersion '19.0.3' sourceSets { main { diff --git a/settings.gradle b/settings.gradle index 1ebb30ec0..f6ba5c517 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ include ':OpenPGP-Keychain' -include ':OpenPGP-Keychain-API:libraries:keychain-api-library' +include ':OpenPGP-Keychain-API:libraries:openpgp-api-library' +include ':OpenPGP-Keychain-API:libraries:openkeychain-api-library' include ':libraries:HtmlTextView' include ':libraries:StickyListHeaders:library' include ':libraries:AndroidBootstrap' diff --git a/tools/checkstyle b/tools/checkstyle new file mode 100755 index 000000000..27aabced2 --- /dev/null +++ b/tools/checkstyle @@ -0,0 +1 @@ +checkstyle -c tools/checkstyle.xml -r OpenPGP-Keychain/src/main/java 2>&1 | egrep -v 'log4j' diff --git a/tools/checkstyle.xml b/tools/checkstyle.xml new file mode 100644 index 000000000..95ef07a90 --- /dev/null +++ b/tools/checkstyle.xml @@ -0,0 +1,356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +