keep up with master
3
.gitignore
vendored
@ -28,3 +28,6 @@ pom.xml.*
|
|||||||
#IntelliJ IDEA
|
#IntelliJ IDEA
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
|
#OS Specific
|
||||||
|
[Tt]humbs.db
|
||||||
|
16
.travis.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
language: java
|
||||||
|
jdk: oraclejdk7
|
||||||
|
before_install:
|
||||||
|
# Install base Android SDK
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq --force-yes libgd2-xpm ia32-libs; fi
|
||||||
|
- wget http://dl.google.com/android/android-sdk_r22.3-linux.tgz
|
||||||
|
- tar xzf android-sdk_r22.3-linux.tgz
|
||||||
|
- export ANDROID_HOME=$PWD/android-sdk-linux
|
||||||
|
- 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.3,android-19,platform-tools,extra-android-support,extra-android-m2repository --no-ui --force
|
||||||
|
install: echo "Installation done"
|
||||||
|
script: gradle assemble -S -q
|
||||||
|
|
@ -1,3 +1,3 @@
|
|||||||
task wrapper(type: Wrapper) {
|
task wrapper(type: Wrapper) {
|
||||||
gradleVersion = '1.10'
|
gradleVersion = '1.10'
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:0.8.3'
|
classpath 'com.android.tools.build:gradle:0.9.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ dependencies {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 19
|
compileSdkVersion 19
|
||||||
buildToolsVersion "19.0.1"
|
buildToolsVersion "19.0.3"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 9
|
minSdkVersion 9
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.sufficientlysecure.keychain.demo"
|
package="org.sufficientlysecure.keychain.demo"
|
||||||
android:versionCode="2"
|
android:versionCode="3"
|
||||||
android:versionName="1.1">
|
android:versionName="2">
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="9"
|
android:minSdkVersion="9"
|
||||||
|
@ -112,11 +112,11 @@ public class IntentActivity extends PreferenceActivity {
|
|||||||
byte[] pubkey = null;
|
byte[] pubkey = null;
|
||||||
try {
|
try {
|
||||||
pubkey = TEST_PUBKEY.getBytes("UTF-8");
|
pubkey = TEST_PUBKEY.getBytes("UTF-8");
|
||||||
|
intent.putExtra(OpenKeychainIntents.IMPORT_KEY_EXTRA_KEY_BYTES, pubkey);
|
||||||
|
startActivity(intent);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
e.printStackTrace();
|
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
|
||||||
}
|
}
|
||||||
intent.putExtra(OpenKeychainIntents.IMPORT_KEY_EXTRA_KEY_BYTES, pubkey);
|
|
||||||
startActivity(intent);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
Toast.makeText(IntentActivity.this, "Activity not found!", Toast.LENGTH_LONG).show();
|
Toast.makeText(IntentActivity.this, "Activity not found!", Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ import android.widget.Toast;
|
|||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpConstants;
|
|
||||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@ -73,25 +72,25 @@ public class OpenPgpProviderActivity extends Activity {
|
|||||||
mSign.setOnClickListener(new View.OnClickListener() {
|
mSign.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
sign(new Bundle());
|
sign(new Intent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mEncrypt.setOnClickListener(new View.OnClickListener() {
|
mEncrypt.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
encrypt(new Bundle());
|
encrypt(new Intent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mSignAndEncrypt.setOnClickListener(new View.OnClickListener() {
|
mSignAndEncrypt.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
signAndEncrypt(new Bundle());
|
signAndEncrypt(new Intent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mDecryptAndVerify.setOnClickListener(new View.OnClickListener() {
|
mDecryptAndVerify.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
decryptAndVerify(new Bundle());
|
decryptAndVerify(new Intent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -169,11 +168,11 @@ public class OpenPgpProviderActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReturn(Bundle result) {
|
public void onReturn(Intent result) {
|
||||||
switch (result.getInt(OpenPgpConstants.RESULT_CODE)) {
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
|
||||||
case OpenPgpConstants.RESULT_CODE_SUCCESS: {
|
case OpenPgpApi.RESULT_CODE_SUCCESS: {
|
||||||
try {
|
try {
|
||||||
Log.d(OpenPgpConstants.TAG, "result: " + os.toByteArray().length
|
Log.d(OpenPgpApi.TAG, "result: " + os.toByteArray().length
|
||||||
+ " str=" + os.toString("UTF-8"));
|
+ " str=" + os.toString("UTF-8"));
|
||||||
|
|
||||||
if (returnToCiphertextField) {
|
if (returnToCiphertextField) {
|
||||||
@ -185,15 +184,15 @@ public class OpenPgpProviderActivity extends Activity {
|
|||||||
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
|
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.getBoolean(OpenPgpConstants.RESULT_SIGNATURE, false)) {
|
if (result.hasExtra(OpenPgpApi.RESULT_SIGNATURE)) {
|
||||||
OpenPgpSignatureResult sigResult
|
OpenPgpSignatureResult sigResult
|
||||||
= result.getParcelable(OpenPgpConstants.RESULT_SIGNATURE);
|
= result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
|
||||||
handleSignature(sigResult);
|
handleSignature(sigResult);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED: {
|
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {
|
||||||
PendingIntent pi = result.getParcelable(OpenPgpConstants.RESULT_INTENT);
|
PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||||
try {
|
try {
|
||||||
OpenPgpProviderActivity.this.startIntentSenderForResult(pi.getIntentSender(),
|
OpenPgpProviderActivity.this.startIntentSenderForResult(pi.getIntentSender(),
|
||||||
requestCode, null, 0, 0, 0);
|
requestCode, null, 0, 0, 0);
|
||||||
@ -202,8 +201,8 @@ public class OpenPgpProviderActivity extends Activity {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpenPgpConstants.RESULT_CODE_ERROR: {
|
case OpenPgpApi.RESULT_CODE_ERROR: {
|
||||||
OpenPgpError error = result.getParcelable(OpenPgpConstants.RESULT_ERRORS);
|
OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
||||||
handleError(error);
|
handleError(error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -211,46 +210,50 @@ public class OpenPgpProviderActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sign(Bundle params) {
|
public void sign(Intent data) {
|
||||||
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
data.setAction(OpenPgpApi.ACTION_SIGN);
|
||||||
|
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
|
|
||||||
InputStream is = getInputstream(false);
|
InputStream is = getInputstream(false);
|
||||||
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||||
api.sign(params, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN));
|
api.executeApiAsync(data, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void encrypt(Bundle params) {
|
public void encrypt(Intent data) {
|
||||||
params.putStringArray(OpenPgpConstants.PARAMS_USER_IDS, mEncryptUserIds.getText().toString().split(","));
|
data.setAction(OpenPgpApi.ACTION_ENCRYPT);
|
||||||
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
data.putExtra(OpenPgpApi.EXTRA_USER_IDS, mEncryptUserIds.getText().toString().split(","));
|
||||||
|
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
|
|
||||||
InputStream is = getInputstream(false);
|
InputStream is = getInputstream(false);
|
||||||
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||||
api.encrypt(params, is, os, new MyCallback(true, os, REQUEST_CODE_ENCRYPT));
|
api.executeApiAsync(data, is, os, new MyCallback(true, os, REQUEST_CODE_ENCRYPT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void signAndEncrypt(Bundle params) {
|
public void signAndEncrypt(Intent data) {
|
||||||
params.putStringArray(OpenPgpConstants.PARAMS_USER_IDS, mEncryptUserIds.getText().toString().split(","));
|
data.setAction(OpenPgpApi.ACTION_SIGN_AND_ENCRYPT);
|
||||||
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
data.putExtra(OpenPgpApi.EXTRA_USER_IDS, mEncryptUserIds.getText().toString().split(","));
|
||||||
|
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
|
|
||||||
InputStream is = getInputstream(false);
|
InputStream is = getInputstream(false);
|
||||||
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||||
api.signAndEncrypt(params, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN_AND_ENCRYPT));
|
api.executeApiAsync(data, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN_AND_ENCRYPT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decryptAndVerify(Bundle params) {
|
public void decryptAndVerify(Intent data) {
|
||||||
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||||
|
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
|
|
||||||
InputStream is = getInputstream(true);
|
InputStream is = getInputstream(true);
|
||||||
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
|
||||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||||
api.decryptAndVerify(params, is, os, new MyCallback(false, os, REQUEST_CODE_DECRYPT_AND_VERIFY));
|
api.executeApiAsync(data, is, os, new MyCallback(false, os, REQUEST_CODE_DECRYPT_AND_VERIFY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -261,29 +264,28 @@ public class OpenPgpProviderActivity extends Activity {
|
|||||||
// try again after user interaction
|
// try again after user interaction
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
/*
|
/*
|
||||||
* The params originally given to the pgp method are are again
|
* The data originally given to the pgp method are are again
|
||||||
* returned here to be used when calling again after user interaction.
|
* returned here to be used when calling again after user interaction.
|
||||||
*
|
*
|
||||||
* They also contain results from the user interaction which happened,
|
* They also contain results from the user interaction which happened,
|
||||||
* for example selected key ids.
|
* for example selected key ids.
|
||||||
*/
|
*/
|
||||||
Bundle params = data.getBundleExtra(OpenPgpConstants.PI_RESULT_PARAMS);
|
|
||||||
|
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case REQUEST_CODE_SIGN: {
|
case REQUEST_CODE_SIGN: {
|
||||||
sign(params);
|
sign(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REQUEST_CODE_ENCRYPT: {
|
case REQUEST_CODE_ENCRYPT: {
|
||||||
encrypt(params);
|
encrypt(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REQUEST_CODE_SIGN_AND_ENCRYPT: {
|
case REQUEST_CODE_SIGN_AND_ENCRYPT: {
|
||||||
signAndEncrypt(params);
|
signAndEncrypt(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REQUEST_CODE_DECRYPT_AND_VERIFY: {
|
case REQUEST_CODE_DECRYPT_AND_VERIFY: {
|
||||||
decryptAndVerify(params);
|
decryptAndVerify(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#Fri Feb 14 01:26:40 CET 2014
|
#Thu Mar 06 22:23:44 CET 2014
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
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
|
||||||
|
@ -5,7 +5,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
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 {
|
android {
|
||||||
compileSdkVersion 19
|
compileSdkVersion 19
|
||||||
buildToolsVersion '19.0.1'
|
buildToolsVersion '19.0.3'
|
||||||
|
|
||||||
// NOTE: We are using the old folder structure to also support Eclipse
|
// NOTE: We are using the old folder structure to also support Eclipse
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="keychain-api-library" default="help">
|
||||||
|
|
||||||
|
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||||
|
It contains the path to the SDK. It should *NOT* be checked into
|
||||||
|
Version Control Systems. -->
|
||||||
|
<property file="local.properties" />
|
||||||
|
|
||||||
|
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||||
|
'android' tool to add properties to it.
|
||||||
|
This is the place to change some Ant specific build properties.
|
||||||
|
Here are some properties you may want to change/update:
|
||||||
|
|
||||||
|
source.dir
|
||||||
|
The name of the source directory. Default is 'src'.
|
||||||
|
out.dir
|
||||||
|
The name of the output directory. Default is 'bin'.
|
||||||
|
|
||||||
|
For other overridable properties, look at the beginning of the rules
|
||||||
|
files in the SDK, at tools/ant/build.xml
|
||||||
|
|
||||||
|
Properties related to the SDK location or the project target should
|
||||||
|
be updated using the 'android' tool with the 'update' action.
|
||||||
|
|
||||||
|
This file is an integral part of the build system for your
|
||||||
|
application and should be checked into Version Control Systems.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<property file="ant.properties" />
|
||||||
|
|
||||||
|
<!-- if sdk.dir was not set from one of the property file, then
|
||||||
|
get it from the ANDROID_HOME env var.
|
||||||
|
This must be done before we load project.properties since
|
||||||
|
the proguard config can use sdk.dir -->
|
||||||
|
<property environment="env" />
|
||||||
|
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||||
|
<isset property="env.ANDROID_HOME" />
|
||||||
|
</condition>
|
||||||
|
|
||||||
|
<!-- The project.properties file is created and updated by the 'android'
|
||||||
|
tool, as well as ADT.
|
||||||
|
|
||||||
|
This contains project specific properties such as project target, and library
|
||||||
|
dependencies. Lower level build properties are stored in ant.properties
|
||||||
|
(or in .classpath for Eclipse projects).
|
||||||
|
|
||||||
|
This file is an integral part of the build system for your
|
||||||
|
application and should be checked into Version Control Systems. -->
|
||||||
|
<loadproperties srcFile="project.properties" />
|
||||||
|
|
||||||
|
<!-- quick check on sdk.dir -->
|
||||||
|
<fail
|
||||||
|
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||||
|
unless="sdk.dir"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Import per project custom build rules if present at the root of the project.
|
||||||
|
This is the place to put custom intermediary targets such as:
|
||||||
|
-pre-build
|
||||||
|
-pre-compile
|
||||||
|
-post-compile (This is typically used for code obfuscation.
|
||||||
|
Compiled code location: ${out.classes.absolute.dir}
|
||||||
|
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||||
|
-post-package
|
||||||
|
-post-build
|
||||||
|
-pre-clean
|
||||||
|
-->
|
||||||
|
<import file="custom_rules.xml" optional="true" />
|
||||||
|
|
||||||
|
<!-- Import the actual build file.
|
||||||
|
|
||||||
|
To customize existing targets, there are two options:
|
||||||
|
- Customize only one target:
|
||||||
|
- copy/paste the target into this file, *before* the
|
||||||
|
<import> task.
|
||||||
|
- customize it to your needs.
|
||||||
|
- Customize the whole content of build.xml
|
||||||
|
- copy/paste the content of the rules files (minus the top node)
|
||||||
|
into this file, replacing the <import> task.
|
||||||
|
- customize to your needs.
|
||||||
|
|
||||||
|
***********************
|
||||||
|
****** IMPORTANT ******
|
||||||
|
***********************
|
||||||
|
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||||
|
in order to avoid having your file be overridden by tools such as "android update project"
|
||||||
|
-->
|
||||||
|
<!-- version-tag: 1 -->
|
||||||
|
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||||
|
|
||||||
|
</project>
|
@ -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 *;
|
||||||
|
#}
|
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.3 KiB |
@ -2,5 +2,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<string name="openpgp_list_preference_none">None</string>
|
<string name="openpgp_list_preference_none">None</string>
|
||||||
|
<string name="openpgp_install_openkeychain_via">Install OpenKeychain via %s</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -18,68 +18,7 @@ package org.openintents.openpgp;
|
|||||||
|
|
||||||
interface IOpenPgpService {
|
interface IOpenPgpService {
|
||||||
|
|
||||||
/**
|
// see OpenPgpApi for documentation
|
||||||
* General extras
|
Intent execute(in Intent data, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
|
||||||
* --------------
|
|
||||||
*
|
|
||||||
* Bundle params:
|
|
||||||
* int api_version (required)
|
|
||||||
* boolean ascii_armor (request ascii armor for ouput)
|
|
||||||
*
|
|
||||||
* returned Bundle:
|
|
||||||
* int result_code (0, 1, or 2 (see OpenPgpConstants))
|
|
||||||
* OpenPgpError error (if result_code == 0)
|
|
||||||
* Intent intent (if result_code == 2)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign only
|
|
||||||
*
|
|
||||||
* optional params:
|
|
||||||
* String passphrase (for key passphrase)
|
|
||||||
*/
|
|
||||||
Bundle sign(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypt
|
|
||||||
*
|
|
||||||
* Bundle params:
|
|
||||||
* long[] key_ids
|
|
||||||
* or
|
|
||||||
* String[] user_ids (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned)
|
|
||||||
*
|
|
||||||
* optional params:
|
|
||||||
* String passphrase (for key passphrase)
|
|
||||||
*/
|
|
||||||
Bundle encrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign and encrypt
|
|
||||||
*
|
|
||||||
* Bundle params:
|
|
||||||
* same as in encrypt()
|
|
||||||
*/
|
|
||||||
Bundle signAndEncrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted,
|
|
||||||
* and also signed-only input.
|
|
||||||
*
|
|
||||||
* returned Bundle:
|
|
||||||
* OpenPgpSignatureResult signature_result
|
|
||||||
*/
|
|
||||||
Bundle decryptAndVerify(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves key ids based on given user ids (=emails)
|
|
||||||
*
|
|
||||||
* Bundle params:
|
|
||||||
* String[] user_ids
|
|
||||||
*
|
|
||||||
* returned Bundle:
|
|
||||||
* long[] key_ids
|
|
||||||
*/
|
|
||||||
Bundle getKeyIds(in Bundle params);
|
|
||||||
|
|
||||||
}
|
}
|
@ -25,10 +25,8 @@ public class OpenPgpSignatureResult implements Parcelable {
|
|||||||
// successfully verified signature, with certified public key
|
// successfully verified signature, with certified public key
|
||||||
public static final int SIGNATURE_SUCCESS_CERTIFIED = 1;
|
public static final int SIGNATURE_SUCCESS_CERTIFIED = 1;
|
||||||
// no public key was found for this signature verification
|
// no public key was found for this signature verification
|
||||||
// you can retrieve the key with
|
|
||||||
// getKeys(new String[] {String.valueOf(signatureResult.getKeyId)}, true, callback)
|
|
||||||
public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2;
|
public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2;
|
||||||
// successfully verified signature, but with certified public key
|
// successfully verified signature, but with uncertified public key
|
||||||
public static final int SIGNATURE_SUCCESS_UNCERTIFIED = 3;
|
public static final int SIGNATURE_SUCCESS_UNCERTIFIED = 3;
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
@ -40,24 +38,40 @@ public class OpenPgpSignatureResult implements Parcelable {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSignatureOnly() {
|
public boolean isSignatureOnly() {
|
||||||
return signatureOnly;
|
return signatureOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSignatureOnly(boolean signatureOnly) {
|
||||||
|
this.signatureOnly = signatureOnly;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
public long getKeyId() {
|
public long getKeyId() {
|
||||||
return keyId;
|
return keyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setKeyId(long keyId) {
|
||||||
|
this.keyId = keyId;
|
||||||
|
}
|
||||||
|
|
||||||
public OpenPgpSignatureResult() {
|
public OpenPgpSignatureResult() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenPgpSignatureResult(int signatureStatus, String signatureUserId,
|
public OpenPgpSignatureResult(int signatureStatus, String signatureUserId,
|
||||||
boolean signatureOnly, long keyId) {
|
boolean signatureOnly, long keyId) {
|
||||||
this.status = signatureStatus;
|
this.status = signatureStatus;
|
||||||
this.signatureOnly = signatureOnly;
|
this.signatureOnly = signatureOnly;
|
||||||
this.userId = signatureUserId;
|
this.userId = signatureUserId;
|
||||||
|
@ -16,137 +16,213 @@
|
|||||||
|
|
||||||
package org.openintents.openpgp.util;
|
package org.openintents.openpgp.util;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Build;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.openintents.openpgp.IOpenPgpService;
|
import org.openintents.openpgp.IOpenPgpService;
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public class OpenPgpApi {
|
public class OpenPgpApi {
|
||||||
|
|
||||||
|
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
|
||||||
|
* --------------
|
||||||
|
*
|
||||||
|
* required extras:
|
||||||
|
* int EXTRA_API_VERSION (always required)
|
||||||
|
*
|
||||||
|
* 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 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
|
||||||
|
*
|
||||||
|
* 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_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign and 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 stream. This methods handles encrypted-only, signed-and-encrypted,
|
||||||
|
* and also signed-only input.
|
||||||
|
*
|
||||||
|
* 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";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get key ids based on given user ids (=emails)
|
||||||
|
*
|
||||||
|
* required extras:
|
||||||
|
* String[] EXTRA_USER_IDS
|
||||||
|
*
|
||||||
|
* returned extras:
|
||||||
|
* long[] EXTRA_KEY_IDS
|
||||||
|
*/
|
||||||
|
public static final String ACTION_GET_KEY_IDS = "org.openintents.openpgp.action.GET_KEY_IDS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_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_AND_ENCRYPT
|
||||||
|
public static final String EXTRA_USER_IDS = "user_ids";
|
||||||
|
public static final String EXTRA_KEY_IDS = "key_ids";
|
||||||
|
// optional extras:
|
||||||
|
public static final String EXTRA_PASSPHRASE = "passphrase";
|
||||||
|
|
||||||
|
// GET_KEY
|
||||||
|
public static final String EXTRA_KEY_ID = "key_id";
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
// 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;
|
IOpenPgpService mService;
|
||||||
Context mContext;
|
Context mContext;
|
||||||
|
|
||||||
private static final int OPERATION_SIGN = 0;
|
|
||||||
private static final int OPERATION_ENCRYPT = 1;
|
|
||||||
private static final int OPERATION_SIGN_ENCRYPT = 2;
|
|
||||||
private static final int OPERATION_DECRYPT_VERIFY = 3;
|
|
||||||
private static final int OPERATION_GET_KEY_IDS = 4;
|
|
||||||
|
|
||||||
public OpenPgpApi(Context context, IOpenPgpService service) {
|
public OpenPgpApi(Context context, IOpenPgpService service) {
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
this.mService = service;
|
this.mService = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bundle sign(InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_SIGN, new Bundle(), is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle sign(Bundle params, InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_SIGN, params, is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sign(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
|
|
||||||
executeApiAsync(OPERATION_SIGN, params, is, os, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle encrypt(InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_ENCRYPT, new Bundle(), is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle encrypt(Bundle params, InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_ENCRYPT, params, is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void encrypt(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
|
|
||||||
executeApiAsync(OPERATION_ENCRYPT, params, is, os, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle signAndEncrypt(InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_SIGN_ENCRYPT, new Bundle(), is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle signAndEncrypt(Bundle params, InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_SIGN_ENCRYPT, params, is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void signAndEncrypt(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
|
|
||||||
executeApiAsync(OPERATION_SIGN_ENCRYPT, params, is, os, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle decryptAndVerify(InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_DECRYPT_VERIFY, new Bundle(), is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle decryptAndVerify(Bundle params, InputStream is, final OutputStream os) {
|
|
||||||
return executeApi(OPERATION_DECRYPT_VERIFY, params, is, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void decryptAndVerify(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
|
|
||||||
executeApiAsync(OPERATION_DECRYPT_VERIFY, params, is, os, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle getKeyIds(Bundle params) {
|
|
||||||
return executeApi(OPERATION_GET_KEY_IDS, params, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IOpenPgpCallback {
|
public interface IOpenPgpCallback {
|
||||||
void onReturn(final Bundle result);
|
void onReturn(final Intent result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OpenPgpAsyncTask extends AsyncTask<Void, Integer, Bundle> {
|
private class OpenPgpAsyncTask extends AsyncTask<Void, Integer, Intent> {
|
||||||
int operationId;
|
Intent data;
|
||||||
Bundle params;
|
|
||||||
InputStream is;
|
InputStream is;
|
||||||
OutputStream os;
|
OutputStream os;
|
||||||
IOpenPgpCallback callback;
|
IOpenPgpCallback callback;
|
||||||
|
|
||||||
private OpenPgpAsyncTask(int operationId, Bundle params, InputStream is, OutputStream os, IOpenPgpCallback callback) {
|
private OpenPgpAsyncTask(Intent data, InputStream is, OutputStream os, IOpenPgpCallback callback) {
|
||||||
this.operationId = operationId;
|
this.data = data;
|
||||||
this.params = params;
|
|
||||||
this.is = is;
|
this.is = is;
|
||||||
this.os = os;
|
this.os = os;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Bundle doInBackground(Void... unused) {
|
protected Intent doInBackground(Void... unused) {
|
||||||
return executeApi(operationId, params, is, os);
|
return executeApi(data, is, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onPostExecute(Bundle result) {
|
protected void onPostExecute(Intent result) {
|
||||||
callback.onReturn(result);
|
callback.onReturn(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeApiAsync(int operationId, Bundle params, InputStream is, OutputStream os, IOpenPgpCallback callback) {
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
new OpenPgpAsyncTask(operationId, params, is, os, callback).execute((Void[]) null);
|
public void executeApiAsync(Intent data, InputStream is, OutputStream os, IOpenPgpCallback callback) {
|
||||||
|
OpenPgpAsyncTask task = new OpenPgpAsyncTask(data, is, os, callback);
|
||||||
|
|
||||||
|
// don't serialize async tasks!
|
||||||
|
// http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
||||||
|
} else {
|
||||||
|
task.execute((Void[]) null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle executeApi(int operationId, Bundle params, InputStream is, OutputStream os) {
|
public Intent executeApi(Intent data, InputStream is, OutputStream os) {
|
||||||
try {
|
try {
|
||||||
params.putInt(OpenPgpConstants.PARAMS_API_VERSION, OpenPgpConstants.API_VERSION);
|
data.putExtra(EXTRA_API_VERSION, OpenPgpApi.API_VERSION);
|
||||||
|
|
||||||
Bundle result = null;
|
Intent result = null;
|
||||||
|
|
||||||
if (operationId == OPERATION_GET_KEY_IDS) {
|
if (ACTION_GET_KEY_IDS.equals(data.getAction())) {
|
||||||
result = mService.getKeyIds(params);
|
result = mService.execute(data, null, null);
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
// send the input and output pfds
|
// pipe the input and output
|
||||||
ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is,
|
ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is,
|
||||||
new ParcelFileDescriptorUtil.IThreadListener() {
|
new ParcelFileDescriptorUtil.IThreadListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onThreadFinished(Thread thread) {
|
public void onThreadFinished(Thread thread) {
|
||||||
Log.d(OpenPgpConstants.TAG, "Copy to service finished");
|
//Log.d(OpenPgpApi.TAG, "Copy to service finished");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os,
|
ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os,
|
||||||
@ -154,45 +230,30 @@ public class OpenPgpApi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onThreadFinished(Thread thread) {
|
public void onThreadFinished(Thread thread) {
|
||||||
Log.d(OpenPgpConstants.TAG, "Service finished writing!");
|
//Log.d(OpenPgpApi.TAG, "Service finished writing!");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// blocks until result is ready
|
// blocks until result is ready
|
||||||
switch (operationId) {
|
result = mService.execute(data, input, output);
|
||||||
case OPERATION_SIGN:
|
|
||||||
result = mService.sign(params, input, output);
|
|
||||||
break;
|
|
||||||
case OPERATION_ENCRYPT:
|
|
||||||
result = mService.encrypt(params, input, output);
|
|
||||||
break;
|
|
||||||
case OPERATION_SIGN_ENCRYPT:
|
|
||||||
result = mService.signAndEncrypt(params, input, output);
|
|
||||||
break;
|
|
||||||
case OPERATION_DECRYPT_VERIFY:
|
|
||||||
result = mService.decryptAndVerify(params, input, output);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// close() is required to halt the TransferThread
|
// close() is required to halt the TransferThread
|
||||||
output.close();
|
output.close();
|
||||||
|
|
||||||
// set class loader to current context to allow unparcelling
|
// set class loader to current context to allow unparcelling
|
||||||
// of OpenPgpError and OpenPgpSignatureResult
|
// of OpenPgpError and OpenPgpSignatureResult
|
||||||
// http://stackoverflow.com/a/3806769
|
// http://stackoverflow.com/a/3806769
|
||||||
result.setClassLoader(mContext.getClassLoader());
|
result.setExtrasClassLoader(mContext.getClassLoader());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(OpenPgpConstants.TAG, "Exception", e);
|
Log.e(OpenPgpApi.TAG, "Exception", e);
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(RESULT_CODE, RESULT_CODE_ERROR);
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
|
result.putExtra(RESULT_ERROR,
|
||||||
new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.openintents.openpgp.util;
|
|
||||||
|
|
||||||
public class OpenPgpConstants {
|
|
||||||
|
|
||||||
public static final String TAG = "OpenPgp API";
|
|
||||||
|
|
||||||
public static final int API_VERSION = 1;
|
|
||||||
public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService";
|
|
||||||
|
|
||||||
|
|
||||||
/* Bundle params */
|
|
||||||
public static final String PARAMS_API_VERSION = "api_version";
|
|
||||||
// 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 PARAMS_REQUEST_ASCII_ARMOR = "ascii_armor";
|
|
||||||
// (for encrypt method)
|
|
||||||
public static final String PARAMS_USER_IDS = "user_ids";
|
|
||||||
public static final String PARAMS_KEY_IDS = "key_ids";
|
|
||||||
// optional parameter:
|
|
||||||
public static final String PARAMS_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 actual error object from RESULT_ERRORS
|
|
||||||
public static final int RESULT_CODE_ERROR = 0;
|
|
||||||
// success!
|
|
||||||
public static final int RESULT_CODE_SUCCESS = 1;
|
|
||||||
// executeServiceMethod intent and do it again with params from intent
|
|
||||||
public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2;
|
|
||||||
|
|
||||||
/* PendingIntent returns */
|
|
||||||
public static final String PI_RESULT_PARAMS = "params";
|
|
||||||
|
|
||||||
}
|
|
@ -23,6 +23,7 @@ import android.content.Intent;
|
|||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.preference.DialogPreference;
|
import android.preference.DialogPreference;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -30,18 +31,24 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.ListAdapter;
|
import android.widget.ListAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import org.sufficientlysecure.keychain.api.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.api.R;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does not extend ListPreference, but is very similar to it!
|
* Does not extend ListPreference, but is very similar to it!
|
||||||
* http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/preference/ListPreference.java/?v=source
|
* http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/preference/ListPreference.java/?v=source
|
||||||
*/
|
*/
|
||||||
public class OpenPgpListPreference extends DialogPreference {
|
public class OpenPgpListPreference extends DialogPreference {
|
||||||
private ArrayList<OpenPgpProviderEntry> mProviderList = new ArrayList<OpenPgpProviderEntry>();
|
private static final String OPENKEYCHAIN_PACKAGE = "org.sufficientlysecure.keychain";
|
||||||
|
private static final String MARKET_INTENT_URI_BASE = "market://details?id=%s";
|
||||||
|
private static final Intent MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse(
|
||||||
|
String.format(MARKET_INTENT_URI_BASE, OPENKEYCHAIN_PACKAGE)));
|
||||||
|
|
||||||
|
private ArrayList<OpenPgpProviderEntry> mLegacyList = new ArrayList<OpenPgpProviderEntry>();
|
||||||
|
private ArrayList<OpenPgpProviderEntry> mList = new ArrayList<OpenPgpProviderEntry>();
|
||||||
|
|
||||||
private String mSelectedPackage;
|
private String mSelectedPackage;
|
||||||
|
|
||||||
public OpenPgpListPreference(Context context, AttributeSet attrs) {
|
public OpenPgpListPreference(Context context, AttributeSet attrs) {
|
||||||
@ -59,16 +66,25 @@ public class OpenPgpListPreference extends DialogPreference {
|
|||||||
* @param simpleName
|
* @param simpleName
|
||||||
* @param icon
|
* @param icon
|
||||||
*/
|
*/
|
||||||
public void addProvider(int position, String packageName, String simpleName, Drawable icon) {
|
public void addLegacyProvider(int position, String packageName, String simpleName, Drawable icon) {
|
||||||
mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon));
|
mLegacyList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPrepareDialogBuilder(Builder builder) {
|
protected void onPrepareDialogBuilder(Builder builder) {
|
||||||
|
mList.clear();
|
||||||
// get providers
|
|
||||||
mProviderList.clear();
|
// add "none"-entry
|
||||||
Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT);
|
mList.add(0, new OpenPgpProviderEntry("",
|
||||||
|
getContext().getString(R.string.openpgp_list_preference_none),
|
||||||
|
getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize)));
|
||||||
|
|
||||||
|
// add all additional (legacy) providers
|
||||||
|
mList.addAll(mLegacyList);
|
||||||
|
|
||||||
|
// search for OpenPGP providers...
|
||||||
|
ArrayList<OpenPgpProviderEntry> providerList = new ArrayList<OpenPgpProviderEntry>();
|
||||||
|
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT);
|
||||||
List<ResolveInfo> resInfo = getContext().getPackageManager().queryIntentServices(intent, 0);
|
List<ResolveInfo> resInfo = getContext().getPackageManager().queryIntentServices(intent, 0);
|
||||||
if (!resInfo.isEmpty()) {
|
if (!resInfo.isEmpty()) {
|
||||||
for (ResolveInfo resolveInfo : resInfo) {
|
for (ResolveInfo resolveInfo : resInfo) {
|
||||||
@ -80,25 +96,40 @@ public class OpenPgpListPreference extends DialogPreference {
|
|||||||
.getPackageManager()));
|
.getPackageManager()));
|
||||||
Drawable icon = resolveInfo.serviceInfo.loadIcon(getContext().getPackageManager());
|
Drawable icon = resolveInfo.serviceInfo.loadIcon(getContext().getPackageManager());
|
||||||
|
|
||||||
mProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon));
|
providerList.add(new OpenPgpProviderEntry(packageName, simpleName, icon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add "none"-entry
|
if (providerList.isEmpty()) {
|
||||||
mProviderList.add(0, new OpenPgpProviderEntry("",
|
// add install links if provider list is empty
|
||||||
getContext().getString(R.string.openpgp_list_preference_none),
|
resInfo = getContext().getPackageManager().queryIntentActivities
|
||||||
getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize)));
|
(MARKET_INTENT, 0);
|
||||||
|
for (ResolveInfo resolveInfo : resInfo) {
|
||||||
|
Intent marketIntent = new Intent(MARKET_INTENT);
|
||||||
|
marketIntent.setPackage(resolveInfo.activityInfo.packageName);
|
||||||
|
Drawable icon = resolveInfo.activityInfo.loadIcon(getContext().getPackageManager());
|
||||||
|
String marketName = String.valueOf(resolveInfo.activityInfo.applicationInfo
|
||||||
|
.loadLabel(getContext().getPackageManager()));
|
||||||
|
String simpleName = String.format(getContext().getString(R.string
|
||||||
|
.openpgp_install_openkeychain_via), marketName);
|
||||||
|
mList.add(new OpenPgpProviderEntry(OPENKEYCHAIN_PACKAGE, simpleName,
|
||||||
|
icon, marketIntent));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// add provider
|
||||||
|
mList.addAll(providerList);
|
||||||
|
}
|
||||||
|
|
||||||
// Init ArrayAdapter with OpenPGP Providers
|
// Init ArrayAdapter with OpenPGP Providers
|
||||||
ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getContext(),
|
ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getContext(),
|
||||||
android.R.layout.select_dialog_singlechoice, android.R.id.text1, mProviderList) {
|
android.R.layout.select_dialog_singlechoice, android.R.id.text1, mList) {
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
// User super class to create the View
|
// User super class to create the View
|
||||||
View v = super.getView(position, convertView, parent);
|
View v = super.getView(position, convertView, parent);
|
||||||
TextView tv = (TextView) v.findViewById(android.R.id.text1);
|
TextView tv = (TextView) v.findViewById(android.R.id.text1);
|
||||||
|
|
||||||
// Put the image on the TextView
|
// Put the image on the TextView
|
||||||
tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, null,
|
tv.setCompoundDrawablesWithIntrinsicBounds(mList.get(position).icon, null,
|
||||||
null, null);
|
null, null);
|
||||||
|
|
||||||
// Add margin between image and text (support various screen densities)
|
// Add margin between image and text (support various screen densities)
|
||||||
@ -114,7 +145,22 @@ public class OpenPgpListPreference extends DialogPreference {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
mSelectedPackage = mProviderList.get(which).packageName;
|
OpenPgpProviderEntry entry = mList.get(which);
|
||||||
|
|
||||||
|
if (entry.intent != null) {
|
||||||
|
/*
|
||||||
|
* Intents are called as activity
|
||||||
|
*
|
||||||
|
* Current approach is to assume the user installed the app.
|
||||||
|
* If he does not, the selected package is not valid.
|
||||||
|
*
|
||||||
|
* However applications should always consider this could happen,
|
||||||
|
* as the user might remove the currently used OpenPGP app.
|
||||||
|
*/
|
||||||
|
getContext().startActivity(entry.intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSelectedPackage = entry.packageName;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clicking on an item simulates the positive button click, and dismisses
|
* Clicking on an item simulates the positive button click, and dismisses
|
||||||
@ -144,9 +190,9 @@ public class OpenPgpListPreference extends DialogPreference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getIndexOfProviderList(String packageName) {
|
private int getIndexOfProviderList(String packageName) {
|
||||||
for (OpenPgpProviderEntry app : mProviderList) {
|
for (OpenPgpProviderEntry app : mList) {
|
||||||
if (app.packageName.equals(packageName)) {
|
if (app.packageName.equals(packageName)) {
|
||||||
return mProviderList.indexOf(app);
|
return mList.indexOf(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +223,7 @@ public class OpenPgpListPreference extends DialogPreference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getEntryByValue(String packageName) {
|
public String getEntryByValue(String packageName) {
|
||||||
for (OpenPgpProviderEntry app : mProviderList) {
|
for (OpenPgpProviderEntry app : mList) {
|
||||||
if (app.packageName.equals(packageName)) {
|
if (app.packageName.equals(packageName)) {
|
||||||
return app.simpleName;
|
return app.simpleName;
|
||||||
}
|
}
|
||||||
@ -190,6 +236,7 @@ public class OpenPgpListPreference extends DialogPreference {
|
|||||||
private String packageName;
|
private String packageName;
|
||||||
private String simpleName;
|
private String simpleName;
|
||||||
private Drawable icon;
|
private Drawable icon;
|
||||||
|
private Intent intent;
|
||||||
|
|
||||||
public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon) {
|
public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon) {
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
@ -197,6 +244,11 @@ public class OpenPgpListPreference extends DialogPreference {
|
|||||||
this.icon = icon;
|
this.icon = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, Intent intent) {
|
||||||
|
this(packageName, simpleName, icon);
|
||||||
|
this.intent = intent;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return simpleName;
|
return simpleName;
|
||||||
|
@ -52,7 +52,7 @@ public class OpenPgpUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAvailable(Context context) {
|
public static boolean isAvailable(Context context) {
|
||||||
Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT);
|
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT);
|
||||||
List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0);
|
List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0);
|
||||||
if (!resInfo.isEmpty()) {
|
if (!resInfo.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -81,21 +81,21 @@ public class ParcelFileDescriptorUtil {
|
|||||||
}
|
}
|
||||||
mOut.flush(); // just to be safe
|
mOut.flush(); // just to be safe
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
//Log.e(OpenPgpConstants.TAG, "TransferThread" + getId() + ": writing failed", e);
|
//Log.e(OpenPgpApi.TAG, "TransferThread" + getId() + ": writing failed", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
mIn.close();
|
mIn.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
//Log.e(OpenPgpConstants.TAG, "TransferThread" + getId(), e);
|
//Log.e(OpenPgpApi.TAG, "TransferThread" + getId(), e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mOut.close();
|
mOut.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
//Log.e(OpenPgpConstants.TAG, "TransferThread" + getId(), e);
|
//Log.e(OpenPgpApi.TAG, "TransferThread" + getId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mListener != null) {
|
if (mListener != null) {
|
||||||
//Log.d(OpenPgpConstants.TAG, "TransferThread " + getId() + " finished!");
|
//Log.d(OpenPgpApi.TAG, "TransferThread " + getId() + " finished!");
|
||||||
mListener.onThreadFinished(this);
|
mListener.onThreadFinished(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ apply plugin: 'android'
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-v4:19.0.1'
|
compile 'com.android.support:support-v4:19.0.1'
|
||||||
compile 'com.android.support:appcompat-v7:19.0.1'
|
compile 'com.android.support:appcompat-v7:19.0.1'
|
||||||
compile project(':libraries:keychain-api-library')
|
compile project(':OpenPGP-Keychain-API:libraries:keychain-api-library')
|
||||||
compile project(':libraries:HtmlTextView')
|
compile project(':libraries:HtmlTextView')
|
||||||
compile project(':libraries:StickyListHeaders:library')
|
compile project(':libraries:StickyListHeaders:library')
|
||||||
compile project(':libraries:AndroidBootstrap')
|
compile project(':libraries:AndroidBootstrap')
|
||||||
@ -18,7 +18,7 @@ dependencies {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 19
|
compileSdkVersion 19
|
||||||
buildToolsVersion "19.0.1"
|
buildToolsVersion "19.0.3"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 9
|
minSdkVersion 9
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.sufficientlysecure.keychain"
|
package="org.sufficientlysecure.keychain"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="23100"
|
android:versionCode="23103"
|
||||||
android:versionName="2.3.1">
|
android:versionName="2.3.1 beta3">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
General remarks
|
General remarks
|
||||||
@ -22,7 +22,8 @@
|
|||||||
Remarks about the ugly android:pathPattern:
|
Remarks about the ugly android:pathPattern:
|
||||||
- We are matching all files with a specific file ending.
|
- We are matching all files with a specific file ending.
|
||||||
This is done in an ugly way because of Android limitations.
|
This is done in an ugly way because of Android limitations.
|
||||||
Read http://stackoverflow.com/questions/1733195/android-intent-filter-for-a-particular-file-extension and http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i/8599921
|
Read http://stackoverflow.com/questions/1733195/android-intent-filter-for-a-particular-file-extension
|
||||||
|
and http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i/8599921
|
||||||
for more information.
|
for more information.
|
||||||
- Do _not_ set mimeType for gpg!
|
- Do _not_ set mimeType for gpg!
|
||||||
Cyanogenmod's file manager will only show Keychain for gpg files if no mimeType is set!
|
Cyanogenmod's file manager will only show Keychain for gpg files if no mimeType is set!
|
||||||
@ -68,30 +69,12 @@
|
|||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<!-- <intent-filter> -->
|
|
||||||
<!-- <action android:name="android.intent.action.SEARCH" /> -->
|
|
||||||
<!-- </intent-filter> -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <meta-data -->
|
|
||||||
<!-- android:name="android.app.searchable" -->
|
|
||||||
<!-- android:resource="@xml/searchable_public_keys" /> -->
|
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.KeyListSecretActivity"
|
android:name=".ui.KeyListSecretActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||||
android:label="@string/title_manage_secret_keys"
|
android:label="@string/title_manage_secret_keys"
|
||||||
android:launchMode="singleTop">
|
android:launchMode="singleTop">
|
||||||
|
|
||||||
<!-- <intent-filter> -->
|
|
||||||
<!-- <action android:name="android.intent.action.SEARCH" /> -->
|
|
||||||
<!-- </intent-filter> -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <meta-data -->
|
|
||||||
<!-- android:name="android.app.searchable" -->
|
|
||||||
<!-- android:resource="@xml/searchable_secret_keys" /> -->
|
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.EditKeyActivity"
|
android:name=".ui.EditKeyActivity"
|
||||||
@ -121,30 +104,12 @@
|
|||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||||
android:label="@string/title_select_recipients"
|
android:label="@string/title_select_recipients"
|
||||||
android:launchMode="singleTop">
|
android:launchMode="singleTop">
|
||||||
|
|
||||||
<!-- <intent-filter> -->
|
|
||||||
<!-- <action android:name="android.intent.action.SEARCH" /> -->
|
|
||||||
<!-- </intent-filter> -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <meta-data -->
|
|
||||||
<!-- android:name="android.app.searchable" -->
|
|
||||||
<!-- android:resource="@xml/searchable_public_keys" /> -->
|
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.SelectSecretKeyActivity"
|
android:name=".ui.SelectSecretKeyActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||||
android:label="@string/title_select_secret_key"
|
android:label="@string/title_select_secret_key"
|
||||||
android:launchMode="singleTop">
|
android:launchMode="singleTop">
|
||||||
|
|
||||||
<!-- <intent-filter> -->
|
|
||||||
<!-- <action android:name="android.intent.action.SEARCH" /> -->
|
|
||||||
<!-- </intent-filter> -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <meta-data -->
|
|
||||||
<!-- android:name="android.app.searchable" -->
|
|
||||||
<!-- android:resource="@xml/searchable_secret_keys" /> -->
|
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.EncryptActivity"
|
android:name=".ui.EncryptActivity"
|
||||||
@ -276,7 +241,16 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ui.PreferencesActivity"
|
android:name=".ui.PreferencesActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||||
android:label="@string/title_preferences" />
|
android:label="@string/title_preferences" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.sufficientlysecure.keychain.ui.PREFS_GEN" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.sufficientlysecure.keychain.ui.PREFS_ADV" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.PreferencesKeyServerActivity"
|
android:name=".ui.PreferencesKeyServerActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||||
@ -454,10 +428,6 @@
|
|||||||
<!--<intent-filter>-->
|
<!--<intent-filter>-->
|
||||||
<!--<action android:name="org.sufficientlysecure.keychain.service.remote.IExtendedApiService" />-->
|
<!--<action android:name="org.sufficientlysecure.keychain.service.remote.IExtendedApiService" />-->
|
||||||
<!--</intent-filter>-->
|
<!--</intent-filter>-->
|
||||||
|
|
||||||
<!--<meta-data-->
|
|
||||||
<!--android:name="api_version"-->
|
|
||||||
<!--android:value="1" />-->
|
|
||||||
<!--</service>-->
|
<!--</service>-->
|
||||||
|
|
||||||
<!-- TODO: authority! Make this API with content provider uris -->
|
<!-- TODO: authority! Make this API with content provider uris -->
|
||||||
|
@ -51,7 +51,7 @@ public final class Constants {
|
|||||||
public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour";
|
public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour";
|
||||||
public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression";
|
public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression";
|
||||||
public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression";
|
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 LANGUAGE = "language";
|
||||||
public static final String FORCE_V3_SIGNATURES = "forceV3Signatures";
|
public static final String FORCE_V3_SIGNATURES = "forceV3Signatures";
|
||||||
public static final String KEY_SERVERS = "keyServers";
|
public static final String KEY_SERVERS = "keyServers";
|
||||||
|
@ -30,7 +30,7 @@ public final class Id {
|
|||||||
public static final class menu {
|
public static final class menu {
|
||||||
|
|
||||||
public static final class option {
|
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 create = 0x21070002;
|
||||||
public static final int about = 0x21070003;
|
public static final int about = 0x21070003;
|
||||||
public static final int manage_public_keys = 0x21070004;
|
public static final int manage_public_keys = 0x21070004;
|
||||||
@ -85,12 +85,12 @@ public final class Id {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final class dialog {
|
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 encrypting = 0x21070002;
|
||||||
public static final int decrypting = 0x21070003;
|
public static final int decrypting = 0x21070003;
|
||||||
public static final int new_pass_phrase = 0x21070004;
|
public static final int new_passphrase = 0x21070004;
|
||||||
public static final int pass_phrases_do_not_match = 0x21070005;
|
public static final int passphrases_do_not_match = 0x21070005;
|
||||||
public static final int no_pass_phrase = 0x21070006;
|
public static final int no_passphrase = 0x21070006;
|
||||||
public static final int saving = 0x21070007;
|
public static final int saving = 0x21070007;
|
||||||
public static final int delete_key = 0x21070008;
|
public static final int delete_key = 0x21070008;
|
||||||
public static final int import_keys = 0x21070009;
|
public static final int import_keys = 0x21070009;
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.spongycastle.bcpg.ArmoredInputStream;
|
import org.spongycastle.bcpg.ArmoredInputStream;
|
||||||
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
||||||
import org.spongycastle.openpgp.PGPCompressedData;
|
import org.spongycastle.openpgp.PGPCompressedData;
|
||||||
@ -36,6 +36,7 @@ import org.spongycastle.openpgp.PGPPublicKey;
|
|||||||
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
|
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
|
||||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.spongycastle.openpgp.PGPSecretKey;
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
import org.spongycastle.openpgp.PGPSignatureList;
|
import org.spongycastle.openpgp.PGPSignatureList;
|
||||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||||
@ -53,7 +54,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
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.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
||||||
@ -75,9 +76,10 @@ public class PgpDecryptVerify {
|
|||||||
private InputData data;
|
private InputData data;
|
||||||
private OutputStream outStream;
|
private OutputStream outStream;
|
||||||
|
|
||||||
private ProgressDialogUpdater progress;
|
private ProgressDialogUpdater progressDialogUpdater;
|
||||||
boolean assumeSymmetric;
|
private boolean assumeSymmetric;
|
||||||
String passphrase;
|
private String passphrase;
|
||||||
|
private long enforcedKeyId;
|
||||||
|
|
||||||
private PgpDecryptVerify(Builder builder) {
|
private PgpDecryptVerify(Builder builder) {
|
||||||
// private Constructor can only be called from Builder
|
// private Constructor can only be called from Builder
|
||||||
@ -85,9 +87,10 @@ public class PgpDecryptVerify {
|
|||||||
this.data = builder.data;
|
this.data = builder.data;
|
||||||
this.outStream = builder.outStream;
|
this.outStream = builder.outStream;
|
||||||
|
|
||||||
this.progress = builder.progress;
|
this.progressDialogUpdater = builder.progressDialogUpdater;
|
||||||
this.assumeSymmetric = builder.assumeSymmetric;
|
this.assumeSymmetric = builder.assumeSymmetric;
|
||||||
this.passphrase = builder.passphrase;
|
this.passphrase = builder.passphrase;
|
||||||
|
this.enforcedKeyId = builder.enforcedKeyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
@ -97,9 +100,10 @@ public class PgpDecryptVerify {
|
|||||||
private OutputStream outStream;
|
private OutputStream outStream;
|
||||||
|
|
||||||
// optional
|
// optional
|
||||||
private ProgressDialogUpdater progress = null;
|
private ProgressDialogUpdater progressDialogUpdater = null;
|
||||||
private boolean assumeSymmetric = false;
|
private boolean assumeSymmetric = false;
|
||||||
private String passphrase = "";
|
private String passphrase = "";
|
||||||
|
private long enforcedKeyId = 0;
|
||||||
|
|
||||||
public Builder(Context context, InputData data, OutputStream outStream) {
|
public Builder(Context context, InputData data, OutputStream outStream) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -107,8 +111,8 @@ public class PgpDecryptVerify {
|
|||||||
this.outStream = outStream;
|
this.outStream = outStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder progress(ProgressDialogUpdater progress) {
|
public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) {
|
||||||
this.progress = progress;
|
this.progressDialogUpdater = progressDialogUpdater;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,20 +126,32 @@ public class PgpDecryptVerify {
|
|||||||
return this;
|
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() {
|
public PgpDecryptVerify build() {
|
||||||
return new PgpDecryptVerify(this);
|
return new PgpDecryptVerify(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateProgress(int message, int current, int total) {
|
public void updateProgress(int message, int current, int total) {
|
||||||
if (progress != null) {
|
if (progressDialogUpdater != null) {
|
||||||
progress.setProgress(message, current, total);
|
progressDialogUpdater.setProgress(message, current, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateProgress(int current, int total) {
|
public void updateProgress(int current, int total) {
|
||||||
if (progress != null) {
|
if (progressDialogUpdater != null) {
|
||||||
progress.setProgress(current, total);
|
progressDialogUpdater.setProgress(current, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,9 +193,8 @@ public class PgpDecryptVerify {
|
|||||||
* @throws PGPException
|
* @throws PGPException
|
||||||
* @throws SignatureException
|
* @throws SignatureException
|
||||||
*/
|
*/
|
||||||
public Bundle execute()
|
public PgpDecryptVerifyResult execute()
|
||||||
throws IOException, PgpGeneralException, PGPException, SignatureException {
|
throws IOException, PgpGeneralException, PGPException, SignatureException {
|
||||||
|
|
||||||
// automatically works with ascii armor input and binary
|
// automatically works with ascii armor input and binary
|
||||||
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
|
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
|
||||||
if (in instanceof ArmoredInputStream) {
|
if (in instanceof ArmoredInputStream) {
|
||||||
@ -207,9 +222,9 @@ public class PgpDecryptVerify {
|
|||||||
* @throws PGPException
|
* @throws PGPException
|
||||||
* @throws SignatureException
|
* @throws SignatureException
|
||||||
*/
|
*/
|
||||||
private Bundle decryptVerify(InputStream in)
|
private PgpDecryptVerifyResult decryptVerify(InputStream in)
|
||||||
throws IOException, PgpGeneralException, PGPException, SignatureException {
|
throws IOException, PgpGeneralException, PGPException, SignatureException {
|
||||||
Bundle returnData = new Bundle();
|
PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
|
||||||
|
|
||||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
||||||
PGPEncryptedDataList enc;
|
PGPEncryptedDataList enc;
|
||||||
@ -277,9 +292,40 @@ public class PgpDecryptVerify {
|
|||||||
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
||||||
secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID());
|
secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID());
|
||||||
if (secretKey != null) {
|
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;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +335,7 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
currentProgress += 5;
|
currentProgress += 5;
|
||||||
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
|
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
|
||||||
PGPPrivateKey privateKey = null;
|
PGPPrivateKey privateKey;
|
||||||
try {
|
try {
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||||
@ -317,6 +363,7 @@ public class PgpDecryptVerify {
|
|||||||
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
|
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
|
||||||
Object dataChunk = plainFact.nextObject();
|
Object dataChunk = plainFact.nextObject();
|
||||||
PGPOnePassSignature signature = null;
|
PGPOnePassSignature signature = null;
|
||||||
|
OpenPgpSignatureResult signatureResult = null;
|
||||||
PGPPublicKey signatureKey = null;
|
PGPPublicKey signatureKey = null;
|
||||||
int signatureIndex = -1;
|
int signatureIndex = -1;
|
||||||
|
|
||||||
@ -334,7 +381,7 @@ public class PgpDecryptVerify {
|
|||||||
if (dataChunk instanceof PGPOnePassSignatureList) {
|
if (dataChunk instanceof PGPOnePassSignatureList) {
|
||||||
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
|
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
|
||||||
|
|
||||||
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
|
signatureResult = new OpenPgpSignatureResult();
|
||||||
PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
|
PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
|
||||||
for (int i = 0; i < sigList.size(); ++i) {
|
for (int i = 0; i < sigList.size(); ++i) {
|
||||||
signature = sigList.get(i);
|
signature = sigList.get(i);
|
||||||
@ -354,12 +401,12 @@ public class PgpDecryptVerify {
|
|||||||
if (signKeyRing != null) {
|
if (signKeyRing != null) {
|
||||||
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
|
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
|
||||||
}
|
}
|
||||||
returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
|
signatureResult.setUserId(userId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
|
signatureResult.setKeyId(signatureKeyId);
|
||||||
|
|
||||||
if (signature != null) {
|
if (signature != null) {
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
|
||||||
@ -367,7 +414,7 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
signature.init(contentVerifierBuilderProvider, signatureKey);
|
signature.init(contentVerifierBuilderProvider, signatureKey);
|
||||||
} else {
|
} else {
|
||||||
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
|
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
dataChunk = plainFact.nextObject();
|
dataChunk = plainFact.nextObject();
|
||||||
@ -405,8 +452,7 @@ public class PgpDecryptVerify {
|
|||||||
try {
|
try {
|
||||||
signature.update(buffer, 0, n);
|
signature.update(buffer, 0, n);
|
||||||
} catch (SignatureException e) {
|
} catch (SignatureException e) {
|
||||||
returnData
|
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
|
||||||
.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
|
|
||||||
signature = null;
|
signature = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,17 +476,20 @@ public class PgpDecryptVerify {
|
|||||||
PGPSignature messageSignature = signatureList.get(signatureIndex);
|
PGPSignature messageSignature = signatureList.get(signatureIndex);
|
||||||
|
|
||||||
// these are not cleartext signatures!
|
// 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
|
//Now check binding signatures
|
||||||
boolean keyBinding_isok = verifyKeyBinding(context, messageSignature, signatureKey);
|
boolean validKeyBinding = verifyKeyBinding(context, messageSignature, signatureKey);
|
||||||
boolean sig_isok = signature.verify(messageSignature);
|
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()) {
|
if (encryptedData.isIntegrityProtected()) {
|
||||||
updateProgress(R.string.progress_verifying_integrity, 95, 100);
|
updateProgress(R.string.progress_verifying_integrity, 95, 100);
|
||||||
|
|
||||||
@ -455,9 +504,12 @@ public class PgpDecryptVerify {
|
|||||||
} else {
|
} else {
|
||||||
// no integrity check
|
// no integrity check
|
||||||
Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
|
Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
|
||||||
|
// TODO: inform user?
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProgress(R.string.progress_done, 100, 100);
|
updateProgress(R.string.progress_done, 100, 100);
|
||||||
|
|
||||||
|
returnData.setSignatureResult(signatureResult);
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,11 +526,12 @@ public class PgpDecryptVerify {
|
|||||||
* @throws PGPException
|
* @throws PGPException
|
||||||
* @throws SignatureException
|
* @throws SignatureException
|
||||||
*/
|
*/
|
||||||
private Bundle verifyCleartextSignature(ArmoredInputStream aIn)
|
private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn)
|
||||||
throws IOException, PgpGeneralException, PGPException, SignatureException {
|
throws IOException, PgpGeneralException, PGPException, SignatureException {
|
||||||
Bundle returnData = new Bundle();
|
PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
|
||||||
|
OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult();
|
||||||
// cleartext signatures are never encrypted ;)
|
// cleartext signatures are never encrypted ;)
|
||||||
returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, true);
|
signatureResult.setSignatureOnly(true);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
|
||||||
@ -504,8 +557,6 @@ public class PgpDecryptVerify {
|
|||||||
byte[] clearText = out.toByteArray();
|
byte[] clearText = out.toByteArray();
|
||||||
outStream.write(clearText);
|
outStream.write(clearText);
|
||||||
|
|
||||||
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
|
|
||||||
|
|
||||||
updateProgress(R.string.progress_processing_signature, 60, 100);
|
updateProgress(R.string.progress_processing_signature, 60, 100);
|
||||||
PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
|
PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
|
||||||
|
|
||||||
@ -533,15 +584,17 @@ public class PgpDecryptVerify {
|
|||||||
if (signKeyRing != null) {
|
if (signKeyRing != null) {
|
||||||
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
|
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
|
||||||
}
|
}
|
||||||
returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
|
signatureResult.setUserId(userId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
|
signatureResult.setKeyId(signatureKeyId);
|
||||||
|
|
||||||
if (signature == null) {
|
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);
|
updateProgress(R.string.progress_done, 100, 100);
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
@ -569,12 +622,17 @@ public class PgpDecryptVerify {
|
|||||||
} while (lookAhead != -1);
|
} while (lookAhead != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean sig_isok = signature.verify();
|
|
||||||
|
|
||||||
//Now check binding signatures
|
//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);
|
updateProgress(R.string.progress_done, 100, 100);
|
||||||
return returnData;
|
return returnData;
|
||||||
@ -582,34 +640,34 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) {
|
private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) {
|
||||||
long signatureKeyId = signature.getKeyID();
|
long signatureKeyId = signature.getKeyID();
|
||||||
boolean keyBinding_isok = false;
|
boolean validKeyBinding = false;
|
||||||
String userId = null;
|
|
||||||
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
|
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
|
||||||
signatureKeyId);
|
signatureKeyId);
|
||||||
PGPPublicKey mKey = null;
|
PGPPublicKey mKey = null;
|
||||||
if (signKeyRing != null) {
|
if (signKeyRing != null) {
|
||||||
mKey = PgpKeyHelper.getMasterKey(signKeyRing);
|
mKey = PgpKeyHelper.getMasterKey(signKeyRing);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature.getKeyID() != mKey.getKeyID()) {
|
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
|
} 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) {
|
private static boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
|
||||||
boolean subkeyBinding_isok = false;
|
boolean validSubkeyBinding = false;
|
||||||
boolean tmp_subkeyBinding_isok = false;
|
boolean validTempSubkeyBinding = false;
|
||||||
boolean primkeyBinding_isok = false;
|
boolean validPrimaryKeyBinding = false;
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
|
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
|
||||||
Iterator<PGPSignature> itr = signingPublicKey.getSignatures();
|
Iterator<PGPSignature> 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?
|
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
|
//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
|
//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.
|
//check and if ok, check primary key binding.
|
||||||
try {
|
try {
|
||||||
sig.init(contentVerifierBuilderProvider, masterPublicKey);
|
sig.init(contentVerifierBuilderProvider, masterPublicKey);
|
||||||
tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey);
|
validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey);
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
continue;
|
continue;
|
||||||
} catch (SignatureException e) {
|
} catch (SignatureException e) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp_subkeyBinding_isok)
|
if (validTempSubkeyBinding)
|
||||||
subkeyBinding_isok = true;
|
validSubkeyBinding = true;
|
||||||
if (tmp_subkeyBinding_isok) {
|
if (validTempSubkeyBinding) {
|
||||||
primkeyBinding_isok = verifyPrimaryBinding(sig.getUnhashedSubPackets(), masterPublicKey, signingPublicKey);
|
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
|
||||||
if (primkeyBinding_isok)
|
masterPublicKey, signingPublicKey);
|
||||||
|
if (validPrimaryKeyBinding)
|
||||||
break;
|
break;
|
||||||
primkeyBinding_isok = verifyPrimaryBinding(sig.getHashedSubPackets(), masterPublicKey, signingPublicKey);
|
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
|
||||||
if (primkeyBinding_isok)
|
masterPublicKey, signingPublicKey);
|
||||||
|
if (validPrimaryKeyBinding)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (subkeyBinding_isok & primkeyBinding_isok);
|
return (validSubkeyBinding & validPrimaryKeyBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
|
private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector Pkts,
|
||||||
boolean primkeyBinding_isok = false;
|
PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
|
boolean validPrimaryKeyBinding = false;
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
PGPSignatureList eSigList;
|
PGPSignatureList eSigList;
|
||||||
|
|
||||||
if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
|
if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
|
||||||
@ -660,8 +722,8 @@ public class PgpDecryptVerify {
|
|||||||
if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
|
if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
|
||||||
try {
|
try {
|
||||||
emSig.init(contentVerifierBuilderProvider, signingPublicKey);
|
emSig.init(contentVerifierBuilderProvider, signingPublicKey);
|
||||||
primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey);
|
validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
|
||||||
if (primkeyBinding_isok)
|
if (validPrimaryKeyBinding)
|
||||||
break;
|
break;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
continue;
|
continue;
|
||||||
@ -671,7 +733,8 @@ public class PgpDecryptVerify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return primkeyBinding_isok;
|
|
||||||
|
return validPrimaryKeyBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.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<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() {
|
||||||
|
public PgpDecryptVerifyResult createFromParcel(final Parcel source) {
|
||||||
|
PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult();
|
||||||
|
vr.symmetricPassphraseNeeded = source.readByte() == 1;
|
||||||
|
vr.keyPassphraseNeeded = source.readByte() == 1;
|
||||||
|
vr.signatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
|
||||||
|
return vr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyResult[] newArray(final int size) {
|
||||||
|
return new PgpDecryptVerifyResult[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -90,8 +90,8 @@ public class PgpImportExport {
|
|||||||
aos.write(keyring.getEncoded());
|
aos.write(keyring.getEncoded());
|
||||||
aos.close();
|
aos.close();
|
||||||
|
|
||||||
String armouredKey = bos.toString("UTF-8");
|
String armoredKey = bos.toString("UTF-8");
|
||||||
server.add(armouredKey);
|
server.add(armoredKey);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -105,7 +105,7 @@ public class PgpKeyOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PGPSecretKey createKey(int algorithmChoice, int keySize, String passPhrase,
|
public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase,
|
||||||
boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
|
boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
|
||||||
PgpGeneralException, InvalidAlgorithmParameterException {
|
PgpGeneralException, InvalidAlgorithmParameterException {
|
||||||
|
|
||||||
@ -113,8 +113,8 @@ public class PgpKeyOperation {
|
|||||||
throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit));
|
throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passPhrase == null) {
|
if (passphrase == null) {
|
||||||
passPhrase = "";
|
passphrase = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int algorithm;
|
int algorithm;
|
||||||
@ -168,7 +168,7 @@ public class PgpKeyOperation {
|
|||||||
// Build key encrypter and decrypter based on passphrase
|
// Build key encrypter and decrypter based on passphrase
|
||||||
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
|
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
|
||||||
PGPEncryptedData.CAST5, sha1Calc)
|
PGPEncryptedData.CAST5, sha1Calc)
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passPhrase.toCharArray());
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
|
||||||
|
|
||||||
return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
|
return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
|
||||||
sha1Calc, isMasterKey, keyEncryptor);
|
sha1Calc, isMasterKey, keyEncryptor);
|
||||||
|
@ -626,7 +626,7 @@ public class ProviderHelper {
|
|||||||
|
|
||||||
String armoredKey = bos.toString("UTF-8");
|
String armoredKey = bos.toString("UTF-8");
|
||||||
|
|
||||||
Log.d(Constants.TAG, "armouredKey:" + armoredKey);
|
Log.d(Constants.TAG, "armoredKey:" + armoredKey);
|
||||||
|
|
||||||
output.add(armoredKey);
|
output.add(armoredKey);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.helper.OtherHelper;
|
|||||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
|
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
|
||||||
@ -176,13 +177,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
|
|||||||
// decrypt/verify
|
// decrypt/verify
|
||||||
public static final String RESULT_DECRYPTED_STRING = "decrypted_message";
|
public static final String RESULT_DECRYPTED_STRING = "decrypted_message";
|
||||||
public static final String RESULT_DECRYPTED_BYTES = "decrypted_data";
|
public static final String RESULT_DECRYPTED_BYTES = "decrypted_data";
|
||||||
public static final String RESULT_SIGNATURE = "signature";
|
public static final String RESULT_DECRYPT_VERIFY_RESULT = "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";
|
|
||||||
|
|
||||||
// import
|
// import
|
||||||
public static final String RESULT_IMPORT_ADDED = "added";
|
public static final String RESULT_IMPORT_ADDED = "added";
|
||||||
@ -198,8 +193,16 @@ public class KeychainIntentService extends IntentService implements ProgressDial
|
|||||||
|
|
||||||
Messenger mMessenger;
|
Messenger mMessenger;
|
||||||
|
|
||||||
|
private boolean mIsCanceled;
|
||||||
|
|
||||||
public KeychainIntentService() {
|
public KeychainIntentService() {
|
||||||
super("ApgService");
|
super("KeychainIntentService");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
this.mIsCanceled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -476,15 +479,17 @@ public class KeychainIntentService extends IntentService implements ProgressDial
|
|||||||
// verifyText and decrypt returning additional resultData values for the
|
// verifyText and decrypt returning additional resultData values for the
|
||||||
// verification of signatures
|
// verification of signatures
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
|
||||||
builder.progress(this);
|
builder.progressDialogUpdater(this);
|
||||||
|
|
||||||
builder.assumeSymmetric(assumeSymmetricEncryption)
|
builder.assumeSymmetric(assumeSymmetricEncryption)
|
||||||
.passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
|
.passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
|
||||||
|
|
||||||
resultData = builder.build().execute();
|
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||||
|
|
||||||
outStream.close();
|
outStream.close();
|
||||||
|
|
||||||
|
resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult);
|
||||||
|
|
||||||
/* Output */
|
/* Output */
|
||||||
|
|
||||||
switch (target) {
|
switch (target) {
|
||||||
@ -733,7 +738,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
|
|||||||
*/
|
*/
|
||||||
// need to have access to the bufferedInput, so we can reuse it for the possible
|
// 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
|
// PGPObject chunks after the first one, e.g. files with several consecutive ASCII
|
||||||
// armour blocks
|
// armor blocks
|
||||||
BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKey));
|
BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKey));
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@ -805,6 +810,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendErrorToHandler(Exception e) {
|
private void sendErrorToHandler(Exception e) {
|
||||||
|
// Service was canceled. Do not send error to handler.
|
||||||
|
if (this.mIsCanceled)
|
||||||
|
return;
|
||||||
|
|
||||||
Log.e(Constants.TAG, "ApgService Exception: ", e);
|
Log.e(Constants.TAG, "ApgService Exception: ", e);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
||||||
@ -814,6 +823,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) {
|
private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) {
|
||||||
|
// Service was canceled. Do not send message to handler.
|
||||||
|
if (this.mIsCanceled)
|
||||||
|
return;
|
||||||
|
|
||||||
Message msg = Message.obtain();
|
Message msg = Message.obtain();
|
||||||
msg.arg1 = arg1;
|
msg.arg1 = arg1;
|
||||||
if (arg2 != null) {
|
if (arg2 != null) {
|
||||||
@ -841,10 +854,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) {
|
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);
|
+ max);
|
||||||
|
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
|
@ -21,6 +21,8 @@ import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
@ -55,9 +57,15 @@ public class KeychainIntentServiceHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, int progressDialogStyle) {
|
public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, int progressDialogStyle) {
|
||||||
|
this(activity, progressDialogMessageId, progressDialogStyle, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId,
|
||||||
|
int progressDialogStyle, boolean cancelable,
|
||||||
|
OnCancelListener onCancelListener) {
|
||||||
this.mActivity = activity;
|
this.mActivity = activity;
|
||||||
this.mProgressDialogFragment = ProgressDialogFragment.newInstance(progressDialogMessageId,
|
this.mProgressDialogFragment = ProgressDialogFragment.newInstance(progressDialogMessageId,
|
||||||
progressDialogStyle);
|
progressDialogStyle, cancelable, onCancelListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showProgressDialog(FragmentActivity activity) {
|
public void showProgressDialog(FragmentActivity activity) {
|
||||||
|
@ -21,21 +21,22 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
|
||||||
import org.openintents.openpgp.IOpenPgpService;
|
import org.openintents.openpgp.IOpenPgpService;
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpConstants;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.spongycastle.util.Arrays;
|
import org.spongycastle.util.Arrays;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
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;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@ -48,7 +49,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
|
|
||||||
private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551;
|
private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551;
|
||||||
private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552;
|
private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552;
|
||||||
|
private static final int PRIVATE_REQUEST_CODE_GET_KEYS = 553;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search database for key ids based on emails.
|
* Search database for key ids based on emails.
|
||||||
@ -56,7 +57,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
* @param encryptionUserIds
|
* @param encryptionUserIds
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Bundle getKeyIdsFromEmails(Bundle params, String[] encryptionUserIds) {
|
private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
|
||||||
// find key ids to given emails in database
|
// find key ids to given emails in database
|
||||||
ArrayList<Long> keyIds = new ArrayList<Long>();
|
ArrayList<Long> keyIds = new ArrayList<Long>();
|
||||||
|
|
||||||
@ -91,21 +92,20 @@ public class OpenPgpService extends RemoteService {
|
|||||||
|
|
||||||
// allow the user to verify pub key selection
|
// allow the user to verify pub key selection
|
||||||
if (missingUserIdsCheck || dublicateUserIdsCheck) {
|
if (missingUserIdsCheck || dublicateUserIdsCheck) {
|
||||||
// build PendingIntent for passphrase input
|
// build PendingIntent
|
||||||
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
||||||
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
|
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
|
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
|
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
|
||||||
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0);
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0);
|
||||||
|
|
||||||
// return PendingIntent to be executed by client
|
// return PendingIntent to be executed by client
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,44 +113,43 @@ public class OpenPgpService extends RemoteService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
|
result.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIdsArray);
|
||||||
result.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIdsArray);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle getPassphraseBundleIntent(Bundle params, long keyId) {
|
private Intent getPassphraseBundleIntent(Intent data, long keyId) {
|
||||||
// build PendingIntent for passphrase input
|
// build PendingIntent for passphrase input
|
||||||
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
||||||
intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE);
|
intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
|
intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
|
||||||
// pass params through to activity that it can be returned again later to repeat pgp operation
|
// pass params through to activity that it can be returned again later to repeat pgp operation
|
||||||
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
||||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
|
||||||
|
|
||||||
// return PendingIntent to be executed by client
|
// return PendingIntent to be executed by client
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle signImpl(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output,
|
private Intent signImpl(Intent data, ParcelFileDescriptor input,
|
||||||
AppSettings appSettings) {
|
ParcelFileDescriptor output, AppSettings appSettings) {
|
||||||
try {
|
try {
|
||||||
boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
|
|
||||||
// get passphrase from cache, if key has "no" passphrase, this returns an empty String
|
// get passphrase from cache, if key has "no" passphrase, this returns an empty String
|
||||||
String passphrase;
|
String passphrase;
|
||||||
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
|
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
||||||
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
|
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
} else {
|
} else {
|
||||||
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
|
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
|
||||||
}
|
}
|
||||||
if (passphrase == null) {
|
if (passphrase == null) {
|
||||||
// get PendingIntent for passphrase input, add it to given params and return to client
|
// get PendingIntent for passphrase input, add it to given params and return to client
|
||||||
Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
|
Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
|
||||||
return passphraseBundle;
|
return passphraseBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,44 +173,43 @@ public class OpenPgpService extends RemoteService {
|
|||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_ERROR,
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
|
|
||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle encryptAndSignImpl(Bundle params, ParcelFileDescriptor input,
|
private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
|
||||||
ParcelFileDescriptor output, AppSettings appSettings,
|
ParcelFileDescriptor output, AppSettings appSettings, boolean sign) {
|
||||||
boolean sign) {
|
|
||||||
try {
|
try {
|
||||||
boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
|
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
|
|
||||||
long[] keyIds;
|
long[] keyIds;
|
||||||
if (params.containsKey(OpenPgpConstants.PARAMS_KEY_IDS)) {
|
if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
|
||||||
keyIds = params.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS);
|
keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
|
||||||
} else if (params.containsKey(OpenPgpConstants.PARAMS_USER_IDS)) {
|
} else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) {
|
||||||
// get key ids based on given user ids
|
// get key ids based on given user ids
|
||||||
String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS);
|
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
|
||||||
// give params through to activity...
|
// give params through to activity...
|
||||||
Bundle result = getKeyIdsFromEmails(params, userIds);
|
Intent result = getKeyIdsFromEmails(data, userIds);
|
||||||
|
|
||||||
if (result.getInt(OpenPgpConstants.RESULT_CODE, 0) == OpenPgpConstants.RESULT_CODE_SUCCESS) {
|
if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) {
|
||||||
keyIds = result.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS);
|
keyIds = result.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
|
||||||
} else {
|
} else {
|
||||||
// if not success -> result contains a PendingIntent for user interaction
|
// if not success -> result contains a PendingIntent for user interaction
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_ERROR,
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
|
|
||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!"));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!"));
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,15 +233,15 @@ public class OpenPgpService extends RemoteService {
|
|||||||
|
|
||||||
if (sign) {
|
if (sign) {
|
||||||
String passphrase;
|
String passphrase;
|
||||||
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
|
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
||||||
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
|
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
} else {
|
} else {
|
||||||
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
||||||
appSettings.getKeyId());
|
appSettings.getKeyId());
|
||||||
}
|
}
|
||||||
if (passphrase == null) {
|
if (passphrase == null) {
|
||||||
// get PendingIntent for passphrase input, add it to given params and return to client
|
// get PendingIntent for passphrase input, add it to given params and return to client
|
||||||
Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
|
Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
|
||||||
return passphraseBundle;
|
return passphraseBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,193 +261,123 @@ public class OpenPgpService extends RemoteService {
|
|||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_ERROR,
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
|
|
||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle decryptAndVerifyImpl(Bundle params, ParcelFileDescriptor input,
|
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
|
||||||
ParcelFileDescriptor output, AppSettings appSettings) {
|
ParcelFileDescriptor output, AppSettings appSettings) {
|
||||||
try {
|
try {
|
||||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||||
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
||||||
OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
||||||
OpenPgpSignatureResult sigResult = null;
|
|
||||||
|
Intent result = new Intent();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// PGPUtil.getDecoderStream(is)
|
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
// TODOs API 2.0:
|
|
||||||
// implement verify-only!
|
|
||||||
// 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: this is not really needed
|
|
||||||
// checked if it is text with BEGIN and END tags
|
|
||||||
// String message = new String(inputBytes);
|
|
||||||
// Log.d(Constants.TAG, "in: " + message);
|
|
||||||
// boolean signedOnly = false;
|
|
||||||
// Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message);
|
|
||||||
// if (matcher.matches()) {
|
|
||||||
// Log.d(Constants.TAG, "PGP_MESSAGE matched");
|
|
||||||
// message = matcher.group(1);
|
|
||||||
// // replace non breakable spaces
|
|
||||||
// message = message.replaceAll("\\xa0", " ");
|
|
||||||
//
|
|
||||||
// // overwrite inputBytes
|
|
||||||
// inputBytes = message.getBytes();
|
|
||||||
// } else {
|
|
||||||
// matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message);
|
|
||||||
// if (matcher.matches()) {
|
|
||||||
// signedOnly = true;
|
|
||||||
// Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched");
|
|
||||||
// message = matcher.group(1);
|
|
||||||
// // replace non breakable spaces
|
|
||||||
// message = message.replaceAll("\\xa0", " ");
|
|
||||||
//
|
|
||||||
// // overwrite inputBytes
|
|
||||||
// inputBytes = message.getBytes();
|
|
||||||
// } else {
|
|
||||||
// Log.d(Constants.TAG, "Nothing matched! Binary?");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// END TODO
|
|
||||||
|
|
||||||
// Log.d(Constants.TAG, "in: " + new String(inputBytes));
|
|
||||||
|
|
||||||
// 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 (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
|
|
||||||
passphrase = params.getString(OpenPgpConstants.PARAMS_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
|
|
||||||
Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
|
|
||||||
return passphraseBundle;
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// build InputData and write into OutputStream
|
|
||||||
long inputLength = is.available();
|
long inputLength = is.available();
|
||||||
InputData inputData = new InputData(is, inputLength);
|
InputData inputData = new InputData(is, inputLength);
|
||||||
|
|
||||||
|
|
||||||
Bundle outputBundle;
|
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
|
||||||
|
builder.assumeSymmetric(false) // no support for symmetric encryption
|
||||||
// if (signedOnly) {
|
.enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption
|
||||||
// outputBundle = builder.build().verifyText();
|
|
||||||
// } else {
|
|
||||||
builder.assumeSymmetric(false)
|
|
||||||
.passphrase(passphrase);
|
.passphrase(passphrase);
|
||||||
|
|
||||||
// Do we want to do this: instead of trying to get the passphrase before
|
// TODO: currently does not support binary signed-only content
|
||||||
// pause stream when passphrase is missing and then resume???
|
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||||
|
|
||||||
// TODO: this also decrypts with other secret keys without passphrase!!!
|
if (decryptVerifyResult.isKeyPassphraseNeeded()) {
|
||||||
outputBundle = builder.build().execute();
|
// 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!");
|
||||||
|
}
|
||||||
|
|
||||||
// outputStream.close();
|
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);
|
||||||
|
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
|
||||||
|
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo");
|
||||||
|
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
||||||
|
|
||||||
// byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(),
|
||||||
|
PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0);
|
||||||
|
|
||||||
// get signature informations from bundle
|
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||||
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);
|
|
||||||
|
|
||||||
int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
|
|
||||||
if (signatureSuccess) {
|
|
||||||
signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED;
|
|
||||||
} else if (signatureUnknown) {
|
|
||||||
signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId,
|
result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
|
||||||
signatureOnly, signatureKeyId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
is.close();
|
is.close();
|
||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle result = new Bundle();
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
|
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_SIGNATURE, sigResult);
|
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_ERROR,
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
|
|
||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bundle getKeyIdsImpl(Bundle params) {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Intent getKeyIdsImpl(Intent data) {
|
||||||
// get key ids based on given user ids
|
// get key ids based on given user ids
|
||||||
String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS);
|
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
|
||||||
Bundle result = getKeyIdsFromEmails(params, userIds);
|
Intent result = getKeyIdsFromEmails(data, userIds);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,30 +387,30 @@ public class OpenPgpService extends RemoteService {
|
|||||||
* - has supported API version
|
* - has supported API version
|
||||||
* - is allowed to call the service (access has been granted)
|
* - is allowed to call the service (access has been granted)
|
||||||
*
|
*
|
||||||
* @param params
|
* @param data
|
||||||
* @return null if everything is okay, or a Bundle with an error/PendingIntent
|
* @return null if everything is okay, or a Bundle with an error/PendingIntent
|
||||||
*/
|
*/
|
||||||
private Bundle checkRequirements(Bundle params) {
|
private Intent checkRequirements(Intent data) {
|
||||||
// params Bundle is required!
|
// params Bundle is required!
|
||||||
if (params == null) {
|
if (data == null) {
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!");
|
OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!");
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error);
|
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// version code is required and needs to correspond to version code of service!
|
// version code is required and needs to correspond to version code of service!
|
||||||
if (params.getInt(OpenPgpConstants.PARAMS_API_VERSION) != OpenPgpConstants.API_VERSION) {
|
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) {
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
|
OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error);
|
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if caller is allowed to access openpgp keychain
|
// check if caller is allowed to access openpgp keychain
|
||||||
Bundle result = isAllowed(params);
|
Intent result = isAllowed(data);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -494,61 +422,30 @@ public class OpenPgpService extends RemoteService {
|
|||||||
private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {
|
private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bundle sign(Bundle params, final ParcelFileDescriptor input, final ParcelFileDescriptor output) {
|
public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) {
|
||||||
|
Intent errorResult = checkRequirements(data);
|
||||||
|
if (errorResult != null) {
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
|
||||||
final AppSettings appSettings = getAppSettings();
|
final AppSettings appSettings = getAppSettings();
|
||||||
|
|
||||||
Bundle errorResult = checkRequirements(params);
|
String action = data.getAction();
|
||||||
if (errorResult != null) {
|
if (OpenPgpApi.ACTION_SIGN.equals(action)) {
|
||||||
return errorResult;
|
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_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_GET_KEY.equals(action)) {
|
||||||
|
return getKeyImpl(data);
|
||||||
|
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
|
||||||
|
return getKeyIdsImpl(data);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return signImpl(params, input, output, appSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bundle encrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
|
|
||||||
final AppSettings appSettings = getAppSettings();
|
|
||||||
|
|
||||||
Bundle errorResult = checkRequirements(params);
|
|
||||||
if (errorResult != null) {
|
|
||||||
return errorResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
return encryptAndSignImpl(params, input, output, appSettings, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bundle signAndEncrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
|
|
||||||
final AppSettings appSettings = getAppSettings();
|
|
||||||
|
|
||||||
Bundle errorResult = checkRequirements(params);
|
|
||||||
if (errorResult != null) {
|
|
||||||
return errorResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
return encryptAndSignImpl(params, input, output, appSettings, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bundle decryptAndVerify(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
|
|
||||||
final AppSettings appSettings = getAppSettings();
|
|
||||||
|
|
||||||
Bundle errorResult = checkRequirements(params);
|
|
||||||
if (errorResult != null) {
|
|
||||||
return errorResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
return decryptAndVerifyImpl(params, input, output, appSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bundle getKeyIds(Bundle params) {
|
|
||||||
Bundle errorResult = checkRequirements(params);
|
|
||||||
if (errorResult != null) {
|
|
||||||
return errorResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getKeyIdsImpl(params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.util.OpenPgpConstants;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
@ -38,10 +38,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
|||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract service class for remote APIs that handle app registration and user input.
|
* Abstract service class for remote APIs that handle app registration and user input.
|
||||||
@ -57,7 +53,7 @@ public abstract class RemoteService extends Service {
|
|||||||
return mContext;
|
return mContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Bundle isAllowed(Bundle params) {
|
protected Intent isAllowed(Intent data) {
|
||||||
try {
|
try {
|
||||||
if (isCallerAllowed(false)) {
|
if (isCallerAllowed(false)) {
|
||||||
|
|
||||||
@ -74,9 +70,9 @@ public abstract class RemoteService extends Service {
|
|||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
Log.e(Constants.TAG, "Should not happen, returning!", e);
|
Log.e(Constants.TAG, "Should not happen, returning!", e);
|
||||||
// return error
|
// return error
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
|
result.putExtra(OpenPgpApi.RESULT_ERROR,
|
||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -86,14 +82,14 @@ public abstract class RemoteService extends Service {
|
|||||||
intent.setAction(RemoteServiceActivity.ACTION_REGISTER);
|
intent.setAction(RemoteServiceActivity.ACTION_REGISTER);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName);
|
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
|
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
|
||||||
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0);
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0);
|
||||||
|
|
||||||
// return PendingIntent to be executed by client
|
// return PendingIntent to be executed by client
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
|
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -103,14 +99,14 @@ public abstract class RemoteService extends Service {
|
|||||||
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
||||||
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
|
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature));
|
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature));
|
||||||
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0);
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0);
|
||||||
|
|
||||||
// return PendingIntent to be executed by client
|
// return PendingIntent to be executed by client
|
||||||
Bundle result = new Bundle();
|
Intent result = new Intent();
|
||||||
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
||||||
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
|
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import android.os.Messenger;
|
|||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.openintents.openpgp.util.OpenPgpConstants;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.sufficientlysecure.htmltextview.HtmlTextView;
|
import org.sufficientlysecure.htmltextview.HtmlTextView;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
@ -51,6 +51,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
|
|
||||||
public static final String EXTRA_MESSENGER = "messenger";
|
public static final String EXTRA_MESSENGER = "messenger";
|
||||||
|
|
||||||
|
public static final String EXTRA_DATA = "data";
|
||||||
|
|
||||||
// passphrase action
|
// passphrase action
|
||||||
public static final String EXTRA_SECRET_KEY_ID = "secret_key_id";
|
public static final String EXTRA_SECRET_KEY_ID = "secret_key_id";
|
||||||
// register action
|
// register action
|
||||||
@ -100,12 +102,9 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
ProviderHelper.insertApiApp(RemoteServiceActivity.this,
|
ProviderHelper.insertApiApp(RemoteServiceActivity.this,
|
||||||
mSettingsFragment.getAppSettings());
|
mSettingsFragment.getAppSettings());
|
||||||
|
|
||||||
// give params through for new service call
|
// give data through for new service call
|
||||||
Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
|
Intent resultData = extras.getParcelable(EXTRA_DATA);
|
||||||
|
RemoteServiceActivity.this.setResult(RESULT_OK, resultData);
|
||||||
Intent finishIntent = new Intent();
|
|
||||||
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, oldParams);
|
|
||||||
RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
|
|
||||||
RemoteServiceActivity.this.finish();
|
RemoteServiceActivity.this.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,9 +127,9 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
mSettingsFragment.setAppSettings(settings);
|
mSettingsFragment.setAppSettings(settings);
|
||||||
} else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
|
} else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
|
||||||
long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);
|
long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);
|
||||||
Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
|
Intent resultData = extras.getParcelable(EXTRA_DATA);
|
||||||
|
|
||||||
showPassphraseDialog(oldParams, secretKeyId);
|
showPassphraseDialog(resultData, secretKeyId);
|
||||||
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
|
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
|
||||||
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
|
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
|
||||||
ArrayList<String> missingUserIds = intent
|
ArrayList<String> missingUserIds = intent
|
||||||
@ -167,13 +166,11 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
// add key ids to params Bundle for new request
|
// add key ids to params Bundle for new request
|
||||||
Bundle params = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
|
Intent resultData = extras.getParcelable(EXTRA_DATA);
|
||||||
params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS,
|
resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS,
|
||||||
mSelectFragment.getSelectedMasterKeyIds());
|
mSelectFragment.getSelectedMasterKeyIds());
|
||||||
|
|
||||||
Intent finishIntent = new Intent();
|
RemoteServiceActivity.this.setResult(RESULT_OK, resultData);
|
||||||
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
|
|
||||||
RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
|
|
||||||
RemoteServiceActivity.this.finish();
|
RemoteServiceActivity.this.finish();
|
||||||
}
|
}
|
||||||
}, R.string.btn_do_not_save, new View.OnClickListener() {
|
}, R.string.btn_do_not_save, new View.OnClickListener() {
|
||||||
@ -222,7 +219,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
RemoteServiceActivity.this.setResult(RESULT_OK);
|
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
|
||||||
RemoteServiceActivity.this.finish();
|
RemoteServiceActivity.this.finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -244,16 +241,14 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
* encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
|
* encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
|
||||||
* for a symmetric passphrase
|
* for a symmetric passphrase
|
||||||
*/
|
*/
|
||||||
private void showPassphraseDialog(final Bundle params, long secretKeyId) {
|
private void showPassphraseDialog(final Intent data, long secretKeyId) {
|
||||||
// Message is received after passphrase is cached
|
// Message is received after passphrase is cached
|
||||||
Handler returnHandler = new Handler() {
|
Handler returnHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
||||||
// return given params again, for calling the service method again
|
// return given params again, for calling the service method again
|
||||||
Intent finishIntent = new Intent();
|
RemoteServiceActivity.this.setResult(RESULT_OK, data);
|
||||||
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
|
|
||||||
RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
|
|
||||||
} else {
|
} else {
|
||||||
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
|
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
|
||||||
}
|
}
|
||||||
@ -273,9 +268,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
} catch (PgpGeneralException e) {
|
} catch (PgpGeneralException e) {
|
||||||
Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!");
|
Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!");
|
||||||
// return given params again, for calling the service method again
|
// return given params again, for calling the service method again
|
||||||
Intent finishIntent = new Intent();
|
setResult(RESULT_OK, data);
|
||||||
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
|
|
||||||
setResult(RESULT_OK, finishIntent);
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
@ -32,6 +33,7 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
|
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
|
||||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
@ -66,6 +68,7 @@ import android.widget.Toast;
|
|||||||
import android.widget.ViewFlipper;
|
import android.widget.ViewFlipper;
|
||||||
|
|
||||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||||
|
import com.devspark.appmsg.AppMsg;
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
public class DecryptActivity extends DrawerActivity {
|
public class DecryptActivity extends DrawerActivity {
|
||||||
@ -233,7 +236,7 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
if (matcher.matches()) {
|
if (matcher.matches()) {
|
||||||
data = matcher.group(1);
|
data = matcher.group(1);
|
||||||
mMessage.setText(data);
|
mMessage.setText(data);
|
||||||
Toast.makeText(this, R.string.using_clipboard_content, Toast.LENGTH_SHORT)
|
AppMsg.makeText(this, R.string.using_clipboard_content, AppMsg.STYLE_INFO)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,17 +423,17 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mInputFilename.equals("")) {
|
if (mInputFilename.equals("")) {
|
||||||
Toast.makeText(this, R.string.no_file_selected, Toast.LENGTH_SHORT).show();
|
AppMsg.makeText(this, R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mInputFilename.startsWith("file")) {
|
if (mInputFilename.startsWith("file")) {
|
||||||
File file = new File(mInputFilename);
|
File file = new File(mInputFilename);
|
||||||
if (!file.exists() || !file.isFile()) {
|
if (!file.exists() || !file.isFile()) {
|
||||||
Toast.makeText(
|
AppMsg.makeText(
|
||||||
this,
|
this,
|
||||||
getString(R.string.error_message,
|
getString(R.string.error_message,
|
||||||
getString(R.string.error_file_not_found)), Toast.LENGTH_SHORT)
|
getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT)
|
||||||
.show();
|
.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -510,14 +513,14 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
inStream = getContentResolver().openInputStream(mContentUri);
|
inStream = getContentResolver().openInputStream(mContentUri);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.e(Constants.TAG, "File not found!", e);
|
Log.e(Constants.TAG, "File not found!", e);
|
||||||
Toast.makeText(this, getString(R.string.error_file_not_found, e.getMessage()),
|
AppMsg.makeText(this, getString(R.string.error_file_not_found, e.getMessage()),
|
||||||
Toast.LENGTH_SHORT).show();
|
AppMsg.STYLE_ALERT).show();
|
||||||
}
|
}
|
||||||
} else if (mDecryptTarget == Id.target.file) {
|
} else if (mDecryptTarget == Id.target.file) {
|
||||||
// check if storage is ready
|
// check if storage is ready
|
||||||
if (!FileHelper.isStorageMounted(mInputFilename)) {
|
if (!FileHelper.isStorageMounted(mInputFilename)) {
|
||||||
Toast.makeText(this, getString(R.string.error_external_storage_not_ready),
|
AppMsg.makeText(this, getString(R.string.error_external_storage_not_ready),
|
||||||
Toast.LENGTH_SHORT).show();
|
AppMsg.STYLE_ALERT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,8 +528,8 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
inStream = new BufferedInputStream(new FileInputStream(mInputFilename));
|
inStream = new BufferedInputStream(new FileInputStream(mInputFilename));
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.e(Constants.TAG, "File not found!", e);
|
Log.e(Constants.TAG, "File not found!", e);
|
||||||
Toast.makeText(this, getString(R.string.error_file_not_found, e.getMessage()),
|
AppMsg.makeText(this, getString(R.string.error_file_not_found, e.getMessage()),
|
||||||
Toast.LENGTH_SHORT).show();
|
AppMsg.STYLE_ALERT).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes());
|
inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes());
|
||||||
@ -556,8 +559,8 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
mAssumeSymmetricEncryption = true;
|
mAssumeSymmetricEncryption = true;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Toast.makeText(this, getString(R.string.error_message, e.getMessage()),
|
AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
|
||||||
Toast.LENGTH_SHORT).show();
|
AppMsg.STYLE_ALERT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,8 +658,8 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
mSignatureKeyId = 0;
|
mSignatureKeyId = 0;
|
||||||
mSignatureLayout.setVisibility(View.GONE);
|
mSignatureLayout.setVisibility(View.GONE);
|
||||||
|
|
||||||
Toast.makeText(DecryptActivity.this, R.string.decryption_successful,
|
AppMsg.makeText(DecryptActivity.this, R.string.decryption_successful,
|
||||||
Toast.LENGTH_SHORT).show();
|
AppMsg.STYLE_INFO).show();
|
||||||
if (mReturnResult) {
|
if (mReturnResult) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtras(returnData);
|
intent.putExtras(returnData);
|
||||||
@ -689,11 +692,15 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE)) {
|
PgpDecryptVerifyResult decryptVerifyResult =
|
||||||
String userId = returnData
|
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
||||||
.getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
|
|
||||||
mSignatureKeyId = returnData
|
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
||||||
.getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
|
|
||||||
|
if (signatureResult != null) {
|
||||||
|
|
||||||
|
String userId = signatureResult.getUserId();
|
||||||
|
mSignatureKeyId = signatureResult.getKeyId();
|
||||||
mUserIdRest.setText("id: "
|
mUserIdRest.setText("id: "
|
||||||
+ PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId));
|
+ PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId));
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
@ -706,19 +713,32 @@ public class DecryptActivity extends DrawerActivity {
|
|||||||
}
|
}
|
||||||
mUserId.setText(userId);
|
mUserId.setText(userId);
|
||||||
|
|
||||||
if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS)) {
|
switch (signatureResult.getStatus()) {
|
||||||
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
|
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
|
||||||
mLookupKey.setVisibility(View.GONE);
|
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
|
||||||
} else if (returnData
|
mLookupKey.setVisibility(View.GONE);
|
||||||
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) {
|
break;
|
||||||
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
|
}
|
||||||
mLookupKey.setVisibility(View.VISIBLE);
|
|
||||||
Toast.makeText(DecryptActivity.this,
|
// TODO!
|
||||||
R.string.unknown_signature,
|
// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
|
||||||
Toast.LENGTH_LONG).show();
|
// break;
|
||||||
} else {
|
// }
|
||||||
mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
|
|
||||||
mLookupKey.setVisibility(View.GONE);
|
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);
|
mSignatureLayout.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity;
|
import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -52,6 +53,7 @@ public class DrawerActivity extends ActionBarActivity {
|
|||||||
private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class,
|
private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class,
|
||||||
EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class,
|
EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class,
|
||||||
KeyListSecretActivity.class, RegisteredAppsListActivity.class };
|
KeyListSecretActivity.class, RegisteredAppsListActivity.class };
|
||||||
|
private Class mSelectedItem;
|
||||||
|
|
||||||
private static final int MENU_ID_PREFERENCE = 222;
|
private static final int MENU_ID_PREFERENCE = 222;
|
||||||
private static final int MENU_ID_HELP = 223;
|
private static final int MENU_ID_HELP = 223;
|
||||||
@ -94,6 +96,17 @@ public class DrawerActivity extends ActionBarActivity {
|
|||||||
getSupportActionBar().setTitle(mTitle);
|
getSupportActionBar().setTitle(mTitle);
|
||||||
// creates call to onPrepareOptionsMenu()
|
// creates call to onPrepareOptionsMenu()
|
||||||
supportInvalidateOptionsMenu();
|
supportInvalidateOptionsMenu();
|
||||||
|
|
||||||
|
// call intent activity if selected
|
||||||
|
if(mSelectedItem != null) {
|
||||||
|
finish();
|
||||||
|
overridePendingTransition(0, 0);
|
||||||
|
|
||||||
|
Intent intent = new Intent(DrawerActivity.this, mSelectedItem);
|
||||||
|
startActivity(intent);
|
||||||
|
// disable animation of activity start
|
||||||
|
overridePendingTransition(0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDrawerOpened(View drawerView) {
|
public void onDrawerOpened(View drawerView) {
|
||||||
@ -182,14 +195,8 @@ public class DrawerActivity extends ActionBarActivity {
|
|||||||
mDrawerList.setItemChecked(position, true);
|
mDrawerList.setItemChecked(position, true);
|
||||||
// setTitle(mDrawerTitles[position]);
|
// setTitle(mDrawerTitles[position]);
|
||||||
mDrawerLayout.closeDrawer(mDrawerList);
|
mDrawerLayout.closeDrawer(mDrawerList);
|
||||||
|
// set selected class
|
||||||
finish();
|
mSelectedItem = mItemsClass[position];
|
||||||
overridePendingTransition(0, 0);
|
|
||||||
|
|
||||||
Intent intent = new Intent(this, mItemsClass[position]);
|
|
||||||
startActivity(intent);
|
|
||||||
// disable animation of activity start
|
|
||||||
overridePendingTransition(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
|
|||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@ -97,7 +98,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
private SectionView mUserIdsView;
|
private SectionView mUserIdsView;
|
||||||
private SectionView mKeysView;
|
private SectionView mKeysView;
|
||||||
|
|
||||||
private String mCurrentPassPhrase = null;
|
private String mCurrentPassphrase = null;
|
||||||
private String mNewPassPhrase = null;
|
private String mNewPassPhrase = null;
|
||||||
private String mSavedNewPassPhrase = null;
|
private String mSavedNewPassPhrase = null;
|
||||||
private boolean mIsPassPhraseSet;
|
private boolean mIsPassPhraseSet;
|
||||||
@ -105,7 +106,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
private boolean mIsBrandNewKeyring = false;
|
private boolean mIsBrandNewKeyring = false;
|
||||||
private MenuItem mSaveButton;
|
private MenuItem mSaveButton;
|
||||||
|
|
||||||
private BootstrapButton mChangePassPhrase;
|
private BootstrapButton mChangePassphrase;
|
||||||
|
|
||||||
private CheckBox mNoPassphrase;
|
private CheckBox mNoPassphrase;
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
private void handleActionCreateKey(Intent intent) {
|
private void handleActionCreateKey(Intent intent) {
|
||||||
Bundle extras = intent.getExtras();
|
Bundle extras = intent.getExtras();
|
||||||
|
|
||||||
mCurrentPassPhrase = "";
|
mCurrentPassphrase = "";
|
||||||
mIsBrandNewKeyring = true;
|
mIsBrandNewKeyring = true;
|
||||||
|
|
||||||
if (extras != null) {
|
if (extras != null) {
|
||||||
@ -190,7 +191,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
if (noPassphrase) {
|
if (noPassphrase) {
|
||||||
// check "no passphrase" checkbox and remove button
|
// check "no passphrase" checkbox and remove button
|
||||||
mNoPassphrase.setChecked(true);
|
mNoPassphrase.setChecked(true);
|
||||||
mChangePassPhrase.setVisibility(View.GONE);
|
mChangePassphrase.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,19 +201,31 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
if (generateDefaultKeys) {
|
if (generateDefaultKeys) {
|
||||||
|
|
||||||
// Send all information needed to service generate keys in other thread
|
// Send all information needed to service generate keys in other thread
|
||||||
Intent serviceIntent = new Intent(this, KeychainIntentService.class);
|
final Intent serviceIntent = new Intent(this, KeychainIntentService.class);
|
||||||
serviceIntent.setAction(KeychainIntentService.ACTION_GENERATE_DEFAULT_RSA_KEYS);
|
serviceIntent.setAction(KeychainIntentService.ACTION_GENERATE_DEFAULT_RSA_KEYS);
|
||||||
|
|
||||||
// fill values for this action
|
// fill values for this action
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE,
|
data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE,
|
||||||
mCurrentPassPhrase);
|
mCurrentPassphrase);
|
||||||
|
|
||||||
serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
|
|
||||||
// Message is received after generating is done in ApgService
|
// Message is received after generating is done in ApgService
|
||||||
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
|
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
|
||||||
this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER) {
|
this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER, true,
|
||||||
|
|
||||||
|
new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
// Stop key generation on cancel
|
||||||
|
stopService(serviceIntent);
|
||||||
|
EditKeyActivity.this.setResult(Activity.RESULT_CANCELED);
|
||||||
|
EditKeyActivity.this.finish();
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
// handle messages by standard ApgHandler first
|
// handle messages by standard ApgHandler first
|
||||||
super.handleMessage(message);
|
super.handleMessage(message);
|
||||||
@ -286,7 +299,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
||||||
mCurrentPassPhrase = PassphraseCacheService.getCachedPassphrase(
|
mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(
|
||||||
EditKeyActivity.this, masterKeyId);
|
EditKeyActivity.this, masterKeyId);
|
||||||
finallySaveClicked();
|
finallySaveClicked();
|
||||||
}
|
}
|
||||||
@ -393,14 +406,14 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentPassPhrase = "";
|
mCurrentPassphrase = "";
|
||||||
|
|
||||||
buildLayout(false);
|
buildLayout(false);
|
||||||
mIsPassPhraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId);
|
mIsPassPhraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId);
|
||||||
if (!mIsPassPhraseSet) {
|
if (!mIsPassPhraseSet) {
|
||||||
// check "no passphrase" checkbox and remove button
|
// check "no passphrase" checkbox and remove button
|
||||||
mNoPassphrase.setChecked(true);
|
mNoPassphrase.setChecked(true);
|
||||||
mChangePassPhrase.setVisibility(View.GONE);
|
mChangePassphrase.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +444,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
// set title based on isPassphraseSet()
|
// set title based on isPassphraseSet()
|
||||||
int title;
|
int title;
|
||||||
if (isPassphraseSet()) {
|
if (isPassphraseSet()) {
|
||||||
title = R.string.title_change_pass_phrase;
|
title = R.string.title_change_passphrase;
|
||||||
} else {
|
} else {
|
||||||
title = R.string.title_set_passphrase;
|
title = R.string.title_set_passphrase;
|
||||||
}
|
}
|
||||||
@ -451,7 +464,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
setContentView(R.layout.edit_key_activity);
|
setContentView(R.layout.edit_key_activity);
|
||||||
|
|
||||||
// find views
|
// 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);
|
mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase);
|
||||||
|
|
||||||
// Build layout based on given userIds and keys
|
// Build layout based on given userIds and keys
|
||||||
@ -473,7 +486,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
|
|
||||||
updatePassPhraseButtonText();
|
updatePassPhraseButtonText();
|
||||||
|
|
||||||
mChangePassPhrase.setOnClickListener(new OnClickListener() {
|
mChangePassphrase.setOnClickListener(new OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
showSetPassphraseDialog();
|
showSetPassphraseDialog();
|
||||||
}
|
}
|
||||||
@ -488,10 +501,10 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
// remove passphrase
|
// remove passphrase
|
||||||
mSavedNewPassPhrase = mNewPassPhrase;
|
mSavedNewPassPhrase = mNewPassPhrase;
|
||||||
mNewPassPhrase = "";
|
mNewPassPhrase = "";
|
||||||
mChangePassPhrase.setVisibility(View.GONE);
|
mChangePassphrase.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
mNewPassPhrase = mSavedNewPassPhrase;
|
mNewPassPhrase = mSavedNewPassPhrase;
|
||||||
mChangePassPhrase.setVisibility(View.VISIBLE);
|
mChangePassphrase.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
somethingChanged();
|
somethingChanged();
|
||||||
}
|
}
|
||||||
@ -545,7 +558,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
if (passphrase == null) {
|
if (passphrase == null) {
|
||||||
showPassphraseDialog(masterKeyId);
|
showPassphraseDialog(masterKeyId);
|
||||||
} else {
|
} else {
|
||||||
mCurrentPassPhrase = passphrase;
|
mCurrentPassphrase = passphrase;
|
||||||
finallySaveClicked();
|
finallySaveClicked();
|
||||||
}
|
}
|
||||||
} catch (PgpGeneralException e) {
|
} catch (PgpGeneralException e) {
|
||||||
@ -581,13 +594,14 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
|
saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
|
||||||
saveParams.keysUsages = getKeysUsages(mKeysView);
|
saveParams.keysUsages = getKeysUsages(mKeysView);
|
||||||
saveParams.newPassPhrase = mNewPassPhrase;
|
saveParams.newPassPhrase = mNewPassPhrase;
|
||||||
saveParams.oldPassPhrase = mCurrentPassPhrase;
|
saveParams.oldPassPhrase = mCurrentPassphrase;
|
||||||
saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
|
saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
|
||||||
saveParams.keys = getKeys(mKeysView);
|
saveParams.keys = getKeys(mKeysView);
|
||||||
|
|
||||||
|
|
||||||
// fill values for this action
|
// fill values for this action
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, masterCanSign);
|
data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, masterCanSign);
|
||||||
data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams);
|
data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams);
|
||||||
|
|
||||||
@ -766,7 +780,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updatePassPhraseButtonText() {
|
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));
|
: getString(R.string.btn_set_passphrase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ import android.widget.Toast;
|
|||||||
import android.widget.ViewFlipper;
|
import android.widget.ViewFlipper;
|
||||||
|
|
||||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||||
|
import com.devspark.appmsg.AppMsg;
|
||||||
|
|
||||||
public class EncryptActivity extends DrawerActivity {
|
public class EncryptActivity extends DrawerActivity {
|
||||||
|
|
||||||
@ -100,8 +101,8 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
|
|
||||||
private int mEncryptTarget;
|
private int mEncryptTarget;
|
||||||
|
|
||||||
private EditText mPassPhrase = null;
|
private EditText mPassphrase = null;
|
||||||
private EditText mPassPhraseAgain = null;
|
private EditText mPassphraseAgain = null;
|
||||||
private CheckBox mAsciiArmor = null;
|
private CheckBox mAsciiArmor = null;
|
||||||
private Spinner mFileCompression = null;
|
private Spinner mFileCompression = null;
|
||||||
|
|
||||||
@ -415,17 +416,17 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
mOutputFilename = guessOutputFilename(mInputFilename);
|
mOutputFilename = guessOutputFilename(mInputFilename);
|
||||||
|
|
||||||
if (mInputFilename.equals("")) {
|
if (mInputFilename.equals("")) {
|
||||||
Toast.makeText(this, R.string.no_file_selected, Toast.LENGTH_SHORT).show();
|
AppMsg.makeText(this, R.string.no_file_selected, AppMsg.STYLE_ALERT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mInputFilename.startsWith("content")) {
|
if (!mInputFilename.startsWith("content")) {
|
||||||
File file = new File(mInputFilename);
|
File file = new File(mInputFilename);
|
||||||
if (!file.exists() || !file.isFile()) {
|
if (!file.exists() || !file.isFile()) {
|
||||||
Toast.makeText(
|
AppMsg.makeText(
|
||||||
this,
|
this,
|
||||||
getString(R.string.error_message,
|
getString(R.string.error_message,
|
||||||
getString(R.string.error_file_not_found)), Toast.LENGTH_SHORT)
|
getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT)
|
||||||
.show();
|
.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -435,16 +436,16 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
// symmetric encryption
|
// symmetric encryption
|
||||||
if (mMode.getCurrentView().getId() == R.id.modeSymmetric) {
|
if (mMode.getCurrentView().getId() == R.id.modeSymmetric) {
|
||||||
boolean gotPassPhrase = false;
|
boolean gotPassPhrase = false;
|
||||||
String passPhrase = mPassPhrase.getText().toString();
|
String passphrase = mPassphrase.getText().toString();
|
||||||
String passPhraseAgain = mPassPhraseAgain.getText().toString();
|
String passphraseAgain = mPassphraseAgain.getText().toString();
|
||||||
if (!passPhrase.equals(passPhraseAgain)) {
|
if (!passphrase.equals(passphraseAgain)) {
|
||||||
Toast.makeText(this, R.string.passphrases_do_not_match, Toast.LENGTH_SHORT).show();
|
AppMsg.makeText(this, R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gotPassPhrase = (passPhrase.length() != 0);
|
gotPassPhrase = (passphrase.length() != 0);
|
||||||
if (!gotPassPhrase) {
|
if (!gotPassPhrase) {
|
||||||
Toast.makeText(this, R.string.passphrase_must_not_be_empty, Toast.LENGTH_SHORT)
|
AppMsg.makeText(this, R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT)
|
||||||
.show();
|
.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -452,13 +453,13 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
boolean encryptIt = (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0);
|
boolean encryptIt = (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0);
|
||||||
// for now require at least one form of encryption for files
|
// for now require at least one form of encryption for files
|
||||||
if (!encryptIt && mEncryptTarget == Id.target.file) {
|
if (!encryptIt && mEncryptTarget == Id.target.file) {
|
||||||
Toast.makeText(this, R.string.select_encryption_key, Toast.LENGTH_SHORT).show();
|
AppMsg.makeText(this, R.string.select_encryption_key, AppMsg.STYLE_ALERT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!encryptIt && mSecretKeyId == 0) {
|
if (!encryptIt && mSecretKeyId == 0) {
|
||||||
Toast.makeText(this, R.string.select_encryption_or_signature_key,
|
AppMsg.makeText(this, R.string.select_encryption_or_signature_key,
|
||||||
Toast.LENGTH_SHORT).show();
|
AppMsg.STYLE_ALERT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,11 +550,11 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
|
|
||||||
if (mMode.getCurrentView().getId() == R.id.modeSymmetric) {
|
if (mMode.getCurrentView().getId() == R.id.modeSymmetric) {
|
||||||
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
Log.d(Constants.TAG, "Symmetric encryption enabled!");
|
||||||
String passPhrase = mPassPhrase.getText().toString();
|
String passphrase = mPassphrase.getText().toString();
|
||||||
if (passPhrase.length() == 0) {
|
if (passphrase.length() == 0) {
|
||||||
passPhrase = null;
|
passphrase = null;
|
||||||
}
|
}
|
||||||
data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passPhrase);
|
data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase);
|
||||||
} else {
|
} else {
|
||||||
mSecretKeyIdToPass = mSecretKeyId;
|
mSecretKeyIdToPass = mSecretKeyId;
|
||||||
encryptionKeyIds = mEncryptionKeyIds;
|
encryptionKeyIds = mEncryptionKeyIds;
|
||||||
@ -618,8 +619,8 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
output = data.getString(KeychainIntentService.RESULT_ENCRYPTED_STRING);
|
output = data.getString(KeychainIntentService.RESULT_ENCRYPTED_STRING);
|
||||||
Log.d(Constants.TAG, "output: " + output);
|
Log.d(Constants.TAG, "output: " + output);
|
||||||
ClipboardReflection.copyToClipboard(EncryptActivity.this, output);
|
ClipboardReflection.copyToClipboard(EncryptActivity.this, output);
|
||||||
Toast.makeText(EncryptActivity.this,
|
AppMsg.makeText(EncryptActivity.this,
|
||||||
R.string.encryption_to_clipboard_successful, Toast.LENGTH_SHORT)
|
R.string.encryption_to_clipboard_successful, AppMsg.STYLE_INFO)
|
||||||
.show();
|
.show();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -640,8 +641,8 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Id.target.file:
|
case Id.target.file:
|
||||||
Toast.makeText(EncryptActivity.this, R.string.encryption_successful,
|
AppMsg.makeText(EncryptActivity.this, R.string.encryption_successful,
|
||||||
Toast.LENGTH_SHORT).show();
|
AppMsg.STYLE_INFO).show();
|
||||||
|
|
||||||
if (mDeleteAfter.isChecked()) {
|
if (mDeleteAfter.isChecked()) {
|
||||||
// Create and show dialog to delete original file
|
// Create and show dialog to delete original file
|
||||||
@ -765,8 +766,8 @@ public class EncryptActivity extends DrawerActivity {
|
|||||||
mMainUserId = (TextView) findViewById(R.id.mainUserId);
|
mMainUserId = (TextView) findViewById(R.id.mainUserId);
|
||||||
mMainUserIdRest = (TextView) findViewById(R.id.mainUserIdRest);
|
mMainUserIdRest = (TextView) findViewById(R.id.mainUserIdRest);
|
||||||
|
|
||||||
mPassPhrase = (EditText) findViewById(R.id.passPhrase);
|
mPassphrase = (EditText) findViewById(R.id.passphrase);
|
||||||
mPassPhraseAgain = (EditText) findViewById(R.id.passPhraseAgain);
|
mPassphraseAgain = (EditText) findViewById(R.id.passphraseAgain);
|
||||||
|
|
||||||
// measure the height of the source_file view and set the message view's min height to that,
|
// 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.
|
// so it fills mSource fully... bit of a hack.
|
||||||
|
@ -17,22 +17,9 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.nfc.NdefMessage;
|
import android.nfc.NdefMessage;
|
||||||
@ -51,6 +38,18 @@ import android.widget.ArrayAdapter;
|
|||||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||||
import com.devspark.appmsg.AppMsg;
|
import com.devspark.appmsg.AppMsg;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.BadImportKeyDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener {
|
public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener {
|
||||||
public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY";
|
public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY";
|
||||||
public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX
|
public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX
|
||||||
@ -236,10 +235,10 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
|
|||||||
* inside your Activity."
|
* inside your Activity."
|
||||||
* <p/>
|
* <p/>
|
||||||
* from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474
|
* from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474
|
||||||
*
|
* <p/>
|
||||||
* In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint,
|
* In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint,
|
||||||
* the fragment would be loaded twice resulting in the query being empty after the second load.
|
* the fragment would be loaded twice resulting in the query being empty after the second load.
|
||||||
*
|
* <p/>
|
||||||
* Our solution:
|
* Our solution:
|
||||||
* To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment
|
* To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment
|
||||||
* checks against mCurrentNavPostition.
|
* checks against mCurrentNavPostition.
|
||||||
@ -395,23 +394,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
|
|||||||
AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
|
AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
|
||||||
.show();
|
.show();
|
||||||
if (bad > 0) {
|
if (bad > 0) {
|
||||||
AlertDialog.Builder alert = new AlertDialog.Builder(
|
BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad);
|
||||||
ImportKeysActivity.this);
|
badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog");
|
||||||
|
|
||||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
|
||||||
alert.setTitle(R.string.warning);
|
|
||||||
|
|
||||||
alert.setMessage(ImportKeysActivity.this.getResources()
|
|
||||||
.getQuantityString(R.plurals.bad_keys_encountered, bad, bad));
|
|
||||||
|
|
||||||
alert.setPositiveButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
dialog.cancel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
alert.setCancelable(true);
|
|
||||||
alert.create().show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,13 @@ import java.util.List;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||||
|
import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader;
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
|
import org.sufficientlysecure.keychain.util.KeyServer;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@ -42,10 +44,11 @@ import android.support.v4.app.LoaderManager;
|
|||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
import com.devspark.appmsg.AppMsg;
|
||||||
|
|
||||||
public class ImportKeysListFragment extends ListFragment implements
|
public class ImportKeysListFragment extends ListFragment implements
|
||||||
LoaderManager.LoaderCallbacks<List<ImportKeysListEntry>> {
|
LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
|
||||||
private static final String ARG_DATA_URI = "uri";
|
private static final String ARG_DATA_URI = "uri";
|
||||||
private static final String ARG_BYTES = "bytes";
|
private static final String ARG_BYTES = "bytes";
|
||||||
private static final String ARG_SERVER_QUERY = "query";
|
private static final String ARG_SERVER_QUERY = "query";
|
||||||
@ -181,11 +184,10 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<List<ImportKeysListEntry>> onCreateLoader(int id, Bundle args) {
|
public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> onCreateLoader(int id, Bundle args) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case LOADER_ID_BYTES: {
|
case LOADER_ID_BYTES: {
|
||||||
InputData inputData = getInputData(mKeyBytes, mDataUri);
|
InputData inputData = getInputData(mKeyBytes, mDataUri);
|
||||||
|
|
||||||
return new ImportKeysListLoader(mActivity, inputData);
|
return new ImportKeysListLoader(mActivity, inputData);
|
||||||
}
|
}
|
||||||
case LOADER_ID_SERVER_QUERY: {
|
case LOADER_ID_SERVER_QUERY: {
|
||||||
@ -198,15 +200,15 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<List<ImportKeysListEntry>> loader,
|
public void onLoadFinished(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader,
|
||||||
List<ImportKeysListEntry> data) {
|
AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) {
|
||||||
// Swap the new cursor in. (The framework will take care of closing the
|
// Swap the new cursor in. (The framework will take care of closing the
|
||||||
// old cursor once we return.)
|
// old cursor once we return.)
|
||||||
|
|
||||||
Log.d(Constants.TAG, "data: " + data);
|
Log.d(Constants.TAG, "data: " + data.getResult());
|
||||||
|
|
||||||
// swap in the real data!
|
// swap in the real data!
|
||||||
mAdapter.setData(data);
|
mAdapter.setData(data.getResult());
|
||||||
mAdapter.notifyDataSetChanged();
|
mAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
setListAdapter(mAdapter);
|
setListAdapter(mAdapter);
|
||||||
@ -222,11 +224,25 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LOADER_ID_SERVER_QUERY:
|
case LOADER_ID_SERVER_QUERY:
|
||||||
Toast.makeText(
|
|
||||||
getActivity(), getResources().getQuantityString(R.plurals.keys_found,
|
Exception error = data.getError();
|
||||||
mAdapter.getCount(), mAdapter.getCount()),
|
|
||||||
Toast.LENGTH_SHORT
|
if(error == null){
|
||||||
).show();
|
AppMsg.makeText(
|
||||||
|
getActivity(), getResources().getQuantityString(R.plurals.keys_found,
|
||||||
|
mAdapter.getCount(), mAdapter.getCount()),
|
||||||
|
AppMsg.STYLE_INFO
|
||||||
|
).show();
|
||||||
|
} 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){
|
||||||
|
AppMsg.makeText(getActivity(), R.string.error_keyserver_query,
|
||||||
|
AppMsg.STYLE_ALERT).show();
|
||||||
|
}else if(error instanceof KeyServer.TooManyResponses){
|
||||||
|
AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses,
|
||||||
|
AppMsg.STYLE_ALERT).show();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -235,7 +251,7 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(Loader<List<ImportKeysListEntry>> loader) {
|
public void onLoaderReset(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader) {
|
||||||
switch (loader.getId()) {
|
switch (loader.getId()) {
|
||||||
case LOADER_ID_BYTES:
|
case LOADER_ID_BYTES:
|
||||||
// Clear the data in the adapter.
|
// Clear the data in the adapter.
|
||||||
|
@ -33,6 +33,7 @@ import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
|
|||||||
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
|
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -45,9 +46,13 @@ import android.support.v4.app.Fragment;
|
|||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
import android.support.v4.view.MenuItemCompat;
|
||||||
|
import android.support.v7.widget.SearchView;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
@ -63,23 +68,25 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
|
|||||||
* Public key list with sticky list headers. It does _not_ extend ListFragment because it uses
|
* Public key list with sticky list headers. It does _not_ extend ListFragment because it uses
|
||||||
* StickyListHeaders library which does not extend upon ListView.
|
* StickyListHeaders library which does not extend upon ListView.
|
||||||
*/
|
*/
|
||||||
public class KeyListPublicFragment extends Fragment implements AdapterView.OnItemClickListener,
|
public class KeyListPublicFragment extends Fragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener,
|
||||||
LoaderManager.LoaderCallbacks<Cursor> {
|
LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
|
|
||||||
private KeyListPublicAdapter mAdapter;
|
private KeyListPublicAdapter mAdapter;
|
||||||
private StickyListHeadersListView mStickyList;
|
private StickyListHeadersListView mStickyList;
|
||||||
|
private String mCurQuery;
|
||||||
|
private SearchView mSearchView;
|
||||||
// empty list layout
|
// empty list layout
|
||||||
private BootstrapButton mButtonEmptyCreate;
|
private BootstrapButton mButtonEmptyCreate;
|
||||||
private BootstrapButton mButtonEmptyImport;
|
private BootstrapButton mButtonEmptyImport;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load custom layout with StickyListView from library
|
* Load custom layout with StickyListView from library
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.key_list_public_fragment, container, false);
|
View view = inflater.inflate(R.layout.key_list_public_fragment, container, false);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create);
|
mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create);
|
||||||
mButtonEmptyCreate.setOnClickListener(new OnClickListener() {
|
mButtonEmptyCreate.setOnClickListener(new OnClickListener() {
|
||||||
|
|
||||||
@ -137,8 +144,6 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
|
|||||||
mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||||
mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() {
|
mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() {
|
||||||
|
|
||||||
private int count = 0;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||||
android.view.MenuInflater inflater = getActivity().getMenuInflater();
|
android.view.MenuInflater inflater = getActivity().getMenuInflater();
|
||||||
@ -172,13 +177,20 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
|
|||||||
showDeleteKeyDialog(mode, ids);
|
showDeleteKeyDialog(mode, ids);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case R.id.menu_key_list_public_multi_select_all: {
|
||||||
|
//Select all
|
||||||
|
int localCount = mStickyList.getCount();
|
||||||
|
for(int k = 0; k < localCount; k++) {
|
||||||
|
mStickyList.setItemChecked(k, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyActionMode(ActionMode mode) {
|
public void onDestroyActionMode(ActionMode mode) {
|
||||||
count = 0;
|
|
||||||
mAdapter.clearSelection();
|
mAdapter.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,13 +198,11 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
|
|||||||
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
|
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
|
||||||
boolean checked) {
|
boolean checked) {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
count++;
|
|
||||||
mAdapter.setNewSelection(position, checked);
|
mAdapter.setNewSelection(position, checked);
|
||||||
} else {
|
} else {
|
||||||
count--;
|
|
||||||
mAdapter.removeSelection(position);
|
mAdapter.removeSelection(position);
|
||||||
}
|
}
|
||||||
|
int count = mAdapter.getCurrentCheckedPosition().size();
|
||||||
String keysSelected = getResources().getQuantityString(
|
String keysSelected = getResources().getQuantityString(
|
||||||
R.plurals.key_list_selected_keys, count, count);
|
R.plurals.key_list_selected_keys, count, count);
|
||||||
mode.setTitle(keysSelected);
|
mode.setTitle(keysSelected);
|
||||||
@ -231,10 +241,15 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
|
|||||||
// This is called when a new Loader needs to be created. This
|
// 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.
|
// sample only has one Loader, so we don't care about the ID.
|
||||||
Uri baseUri = KeyRings.buildPublicKeyRingsUri();
|
Uri baseUri = KeyRings.buildPublicKeyRingsUri();
|
||||||
|
String where = null;
|
||||||
|
String whereArgs[] = null;
|
||||||
|
if(mCurQuery != null){
|
||||||
|
where = KeychainContract.UserIds.USER_ID + " LIKE ?";
|
||||||
|
whereArgs = new String[]{mCurQuery+"%"};
|
||||||
|
}
|
||||||
// Now create and return a CursorLoader that will take care of
|
// Now create and return a CursorLoader that will take care of
|
||||||
// creating a Cursor for the data being displayed.
|
// 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
|
@Override
|
||||||
@ -276,7 +291,8 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
|
|||||||
viewIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id)));
|
viewIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id)));
|
||||||
startActivity(viewIntent);
|
startActivity(viewIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TargetApi(11)
|
||||||
public void encrypt(ActionMode mode, long[] keyRingRowIds) {
|
public void encrypt(ActionMode mode, long[] keyRingRowIds) {
|
||||||
// get master key ids from row ids
|
// get master key ids from row ids
|
||||||
long[] keyRingIds = new long[keyRingRowIds.length];
|
long[] keyRingIds = new long[keyRingRowIds.length];
|
||||||
@ -298,6 +314,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
|
|||||||
*
|
*
|
||||||
* @param keyRingRowIds
|
* @param keyRingRowIds
|
||||||
*/
|
*/
|
||||||
|
@TargetApi(11)
|
||||||
public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
|
public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
|
||||||
// Message is received after key is deleted
|
// Message is received after key is deleted
|
||||||
Handler returnHandler = new Handler() {
|
Handler returnHandler = new Handler() {
|
||||||
@ -332,4 +349,34 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
|
|||||||
deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
|
deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
|
|
||||||
|
// Get the searchview
|
||||||
|
MenuItem searchItem = menu.findItem(R.id.menu_key_list_public_search);
|
||||||
|
mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
|
||||||
|
|
||||||
|
// Execute this when searching
|
||||||
|
mSearchView.setOnQueryTextListener(this);
|
||||||
|
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextSubmit(String s) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextChange(String s) {
|
||||||
|
// Called when the action bar search text has changed. Update
|
||||||
|
// the search filter, and restart the loader to do a new query
|
||||||
|
// with this filter.
|
||||||
|
String newQuery = !TextUtils.isEmpty(s) ? s : null;
|
||||||
|
mCurQuery = newQuery;
|
||||||
|
getLoaderManager().restartLoader(0, null, this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@ import org.sufficientlysecure.keychain.ui.adapter.KeyListSecretAdapter;
|
|||||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -81,8 +82,6 @@ public class KeyListSecretFragment extends ListFragment implements
|
|||||||
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||||
getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
|
getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
|
||||||
|
|
||||||
private int count = 0;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||||
android.view.MenuInflater inflater = getActivity().getMenuInflater();
|
android.view.MenuInflater inflater = getActivity().getMenuInflater();
|
||||||
@ -112,13 +111,20 @@ public class KeyListSecretFragment extends ListFragment implements
|
|||||||
showDeleteKeyDialog(mode, ids);
|
showDeleteKeyDialog(mode, ids);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case R.id.menu_key_list_public_multi_select_all: {
|
||||||
|
//Select all
|
||||||
|
int localCount = getListView().getCount();
|
||||||
|
for(int k = 0; k < localCount; k++) {
|
||||||
|
getListView().setItemChecked(k, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyActionMode(ActionMode mode) {
|
public void onDestroyActionMode(ActionMode mode) {
|
||||||
count = 0;
|
|
||||||
mAdapter.clearSelection();
|
mAdapter.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,13 +132,12 @@ public class KeyListSecretFragment extends ListFragment implements
|
|||||||
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
|
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
|
||||||
boolean checked) {
|
boolean checked) {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
count++;
|
|
||||||
mAdapter.setNewSelection(position, checked);
|
mAdapter.setNewSelection(position, checked);
|
||||||
} else {
|
} else {
|
||||||
count--;
|
|
||||||
mAdapter.removeSelection(position);
|
mAdapter.removeSelection(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int count = getListView().getCheckedItemCount();
|
||||||
String keysSelected = getResources().getQuantityString(
|
String keysSelected = getResources().getQuantityString(
|
||||||
R.plurals.key_list_selected_keys, count, count);
|
R.plurals.key_list_selected_keys, count, count);
|
||||||
mode.setTitle(keysSelected);
|
mode.setTitle(keysSelected);
|
||||||
@ -209,6 +214,7 @@ public class KeyListSecretFragment extends ListFragment implements
|
|||||||
*
|
*
|
||||||
* @param keyRingRowIds
|
* @param keyRingRowIds
|
||||||
*/
|
*/
|
||||||
|
@TargetApi(11)
|
||||||
public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
|
public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
|
||||||
// Message is received after key is deleted
|
// Message is received after key is deleted
|
||||||
Handler returnHandler = new Handler() {
|
Handler returnHandler = new Handler() {
|
||||||
|
@ -24,24 +24,28 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
|
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
public class PreferencesActivity extends PreferenceActivity {
|
public class PreferencesActivity extends PreferenceActivity {
|
||||||
private IntegerListPreference mPassPhraseCacheTtl = null;
|
|
||||||
private IntegerListPreference mEncryptionAlgorithm = null;
|
public final static String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN";
|
||||||
private IntegerListPreference mHashAlgorithm = null;
|
public final static String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
|
||||||
private IntegerListPreference mMessageCompression = null;
|
|
||||||
private IntegerListPreference mFileCompression = null;
|
|
||||||
private CheckBoxPreference mAsciiArmour = null;
|
|
||||||
private CheckBoxPreference mForceV3Signatures = null;
|
|
||||||
private PreferenceScreen mKeyServerPreference = null;
|
private PreferenceScreen mKeyServerPreference = null;
|
||||||
private Preferences mPreferences;
|
private static Preferences mPreferences;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -53,22 +57,219 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
// actionBar.setDisplayHomeAsUpEnabled(false);
|
// actionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
// actionBar.setHomeButtonEnabled(false);
|
// actionBar.setHomeButtonEnabled(false);
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
//addPreferencesFromResource(R.xml.preferences);
|
||||||
|
String action = getIntent().getAction();
|
||||||
|
|
||||||
mPassPhraseCacheTtl = (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL);
|
if (action != null && action.equals(ACTION_PREFS_GEN)) {
|
||||||
mPassPhraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl());
|
addPreferencesFromResource(R.xml.gen_preferences);
|
||||||
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
|
|
||||||
mPassPhraseCacheTtl
|
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<Header> 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() {
|
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
mPassPhraseCacheTtl.setValue(newValue.toString());
|
mPassphraseCacheTtl.setValue(newValue.toString());
|
||||||
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
|
mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry());
|
||||||
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
|
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
|
||||||
return false;
|
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,
|
int valueIds[] = { PGPEncryptedData.AES_128, PGPEncryptedData.AES_192,
|
||||||
PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH,
|
PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH,
|
||||||
PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES,
|
PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES,
|
||||||
@ -93,8 +294,10 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
return false;
|
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,
|
valueIds = new int[] { HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160,
|
||||||
HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256,
|
HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256,
|
||||||
HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, };
|
HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, };
|
||||||
@ -116,19 +319,10 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mMessageCompression = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION);
|
private static void initializeMessageCompression
|
||||||
valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip,
|
(final IntegerListPreference mMessageCompression, int[] valueIds, String[] entries, String[] values) {
|
||||||
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];
|
|
||||||
}
|
|
||||||
mMessageCompression.setEntries(entries);
|
mMessageCompression.setEntries(entries);
|
||||||
mMessageCompression.setEntryValues(values);
|
mMessageCompression.setEntryValues(values);
|
||||||
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
|
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
|
||||||
@ -143,8 +337,10 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
return false;
|
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.setEntries(entries);
|
||||||
mFileCompression.setEntryValues(values);
|
mFileCompression.setEntryValues(values);
|
||||||
mFileCompression.setValue("" + mPreferences.getDefaultFileCompression());
|
mFileCompression.setValue("" + mPreferences.getDefaultFileCompression());
|
||||||
@ -157,8 +353,9 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mAsciiArmour = (CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR);
|
private static void initializeAsciiArmour(final CheckBoxPreference mAsciiArmour) {
|
||||||
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
|
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
|
||||||
mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
@ -167,8 +364,9 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mForceV3Signatures = (CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES);
|
private static void initializeForceV3Signatures(final CheckBoxPreference mForceV3Signatures) {
|
||||||
mForceV3Signatures.setChecked(mPreferences.getForceV3Signatures());
|
mForceV3Signatures.setChecked(mPreferences.getForceV3Signatures());
|
||||||
mForceV3Signatures
|
mForceV3Signatures
|
||||||
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
@ -178,43 +376,5 @@ public class PreferencesActivity extends PreferenceActivity {
|
|||||||
return false;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -38,17 +38,22 @@ import android.os.Bundle;
|
|||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
public class SelectPublicKeyFragment extends ListFragmentWorkaround implements
|
public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher,
|
||||||
LoaderManager.LoaderCallbacks<Cursor> {
|
LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids";
|
public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids";
|
||||||
|
|
||||||
private Activity mActivity;
|
private Activity mActivity;
|
||||||
private SelectKeyCursorAdapter mAdapter;
|
private SelectKeyCursorAdapter mAdapter;
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
|
private EditText mSearchView;
|
||||||
private long mSelectedMasterKeyIds[];
|
private long mSelectedMasterKeyIds[];
|
||||||
|
private String mCurQuery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
@ -67,7 +72,8 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
mSearchView = (EditText)getActivity().findViewById(R.id.select_public_key_search);
|
||||||
|
mSearchView.addTextChangedListener(this);
|
||||||
mSelectedMasterKeyIds = getArguments().getLongArray(ARG_PRESELECTED_KEY_IDS);
|
mSelectedMasterKeyIds = getArguments().getLongArray(ARG_PRESELECTED_KEY_IDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +88,6 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements
|
|||||||
mListView = getListView();
|
mListView = getListView();
|
||||||
|
|
||||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||||
|
|
||||||
// Give some text to display if there is no data. In a real
|
// Give some text to display if there is no data. In a real
|
||||||
// application this would come from a resource.
|
// application this would come from a resource.
|
||||||
setEmptyText(getString(R.string.list_empty));
|
setEmptyText(getString(R.string.list_empty));
|
||||||
@ -220,10 +225,16 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements
|
|||||||
// sort by selected master keys
|
// sort by selected master keys
|
||||||
orderBy = inMasterKeyList + " DESC, " + orderBy;
|
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
|
// Now create and return a CursorLoader that will take care of
|
||||||
// creating a Cursor for the data being displayed.
|
// 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
|
@Override
|
||||||
@ -250,4 +261,21 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements
|
|||||||
// longer using it.
|
// longer using it.
|
||||||
mAdapter.swapCursor(null);
|
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) {
|
||||||
|
String newQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null;
|
||||||
|
mCurQuery = newQuery;
|
||||||
|
getLoaderManager().restartLoader(0, null, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui.adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AsyncTaskResultWrapper is used to wrap a result from a AsyncTask (for example: Loader).
|
||||||
|
* You can pass the result and an exception in it if an error occurred.
|
||||||
|
* Concept found at:
|
||||||
|
* https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader
|
||||||
|
* @param <T> - Typ of the result which is wrapped
|
||||||
|
*/
|
||||||
|
public class AsyncTaskResultWrapper <T>{
|
||||||
|
|
||||||
|
private final T result;
|
||||||
|
private final Exception error;
|
||||||
|
|
||||||
|
public AsyncTaskResultWrapper(T result, Exception error){
|
||||||
|
this.result = result;
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Exception getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,12 +33,13 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.v4.content.AsyncTaskLoader;
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
|
|
||||||
public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> {
|
public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
|
||||||
Context mContext;
|
Context mContext;
|
||||||
|
|
||||||
InputData mInputData;
|
InputData mInputData;
|
||||||
|
|
||||||
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>();
|
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>();
|
||||||
|
AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
|
||||||
|
|
||||||
public ImportKeysListLoader(Context context, InputData inputData) {
|
public ImportKeysListLoader(Context context, InputData inputData) {
|
||||||
super(context);
|
super(context);
|
||||||
@ -47,15 +48,18 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ImportKeysListEntry> loadInBackground() {
|
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
|
||||||
|
|
||||||
|
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, null);
|
||||||
|
|
||||||
if (mInputData == null) {
|
if (mInputData == null) {
|
||||||
Log.e(Constants.TAG, "Input data is null!");
|
Log.e(Constants.TAG, "Input data is null!");
|
||||||
return data;
|
return entryListWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
generateListOfKeyrings(mInputData);
|
generateListOfKeyrings(mInputData);
|
||||||
|
|
||||||
return data;
|
return entryListWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -77,7 +81,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deliverResult(List<ImportKeysListEntry> data) {
|
public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) {
|
||||||
super.deliverResult(data);
|
super.deliverResult(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +97,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt
|
|||||||
|
|
||||||
// need to have access to the bufferedInput, so we can reuse it for the possible
|
// 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
|
// PGPObject chunks after the first one, e.g. files with several consecutive ASCII
|
||||||
// armour blocks
|
// armor blocks
|
||||||
BufferedInputStream bufferedInput = new BufferedInputStream(progressIn);
|
BufferedInputStream bufferedInput = new BufferedInputStream(progressIn);
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -26,15 +26,15 @@ import org.sufficientlysecure.keychain.util.KeyServer;
|
|||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> {
|
public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
|
||||||
Context mContext;
|
Context mContext;
|
||||||
|
|
||||||
String mServerQuery;
|
String mServerQuery;
|
||||||
String mKeyServer;
|
String mKeyServer;
|
||||||
|
|
||||||
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>();
|
private ArrayList<ImportKeysListEntry> entryList = new ArrayList<ImportKeysListEntry>();
|
||||||
|
private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
|
||||||
|
|
||||||
public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) {
|
public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) {
|
||||||
super(context);
|
super(context);
|
||||||
@ -44,15 +44,18 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ImportKeysListEntry> loadInBackground() {
|
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
|
||||||
|
|
||||||
|
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
|
||||||
|
|
||||||
if (mServerQuery == null) {
|
if (mServerQuery == null) {
|
||||||
Log.e(Constants.TAG, "mServerQuery is null!");
|
Log.e(Constants.TAG, "mServerQuery is null!");
|
||||||
return data;
|
return entryListWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
queryServer(mServerQuery, mKeyServer);
|
queryServer(mServerQuery, mKeyServer);
|
||||||
|
|
||||||
return data;
|
return entryListWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -74,7 +77,7 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deliverResult(List<ImportKeysListEntry> data) {
|
public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) {
|
||||||
super.deliverResult(data);
|
super.deliverResult(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,13 +90,17 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL
|
|||||||
ArrayList<ImportKeysListEntry> searchResult = server.search(query);
|
ArrayList<ImportKeysListEntry> searchResult = server.search(query);
|
||||||
|
|
||||||
// add result to data
|
// add result to data
|
||||||
data.addAll(searchResult);
|
entryList.addAll(searchResult);
|
||||||
|
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
|
||||||
} catch (KeyServer.InsufficientQuery e) {
|
} catch (KeyServer.InsufficientQuery e) {
|
||||||
Log.e(Constants.TAG, "InsufficientQuery", e);
|
Log.e(Constants.TAG, "InsufficientQuery", e);
|
||||||
|
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
|
||||||
} catch (KeyServer.QueryException e) {
|
} catch (KeyServer.QueryException e) {
|
||||||
Log.e(Constants.TAG, "QueryException", e);
|
Log.e(Constants.TAG, "QueryException", e);
|
||||||
|
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
|
||||||
} catch (KeyServer.TooManyResponses e) {
|
} catch (KeyServer.TooManyResponses e) {
|
||||||
Log.e(Constants.TAG, "TooManyResponses", e);
|
Log.e(Constants.TAG, "TooManyResponses", e);
|
||||||
|
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea
|
|||||||
*/
|
*/
|
||||||
// default color
|
// default color
|
||||||
v.setBackgroundColor(Color.TRANSPARENT);
|
v.setBackgroundColor(Color.TRANSPARENT);
|
||||||
if (mSelection.get(position) != null) {
|
if (mSelection.get(position) != null && mSelection.get(position).booleanValue()) {
|
||||||
// this is a selected position, change color!
|
// this is a selected position, change color!
|
||||||
v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
|
v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui.dialog;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
|
||||||
|
public class BadImportKeyDialogFragment extends DialogFragment {
|
||||||
|
private static final String ARG_BAD_IMPORT = "bad_import";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of this Bad Import Key DialogFragment
|
||||||
|
*
|
||||||
|
* @param bad
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static BadImportKeyDialogFragment newInstance(int bad) {
|
||||||
|
BadImportKeyDialogFragment frag = new BadImportKeyDialogFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
|
||||||
|
args.putInt(ARG_BAD_IMPORT, bad);
|
||||||
|
frag.setArguments(args);
|
||||||
|
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final FragmentActivity activity = getActivity();
|
||||||
|
final int badImport = getArguments().getInt(ARG_BAD_IMPORT);
|
||||||
|
|
||||||
|
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
||||||
|
alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
||||||
|
alert.setTitle(R.string.warning);
|
||||||
|
alert.setMessage(activity.getResources()
|
||||||
|
.getQuantityString(R.plurals.bad_keys_encountered, badImport, badImport));
|
||||||
|
alert.setPositiveButton(android.R.string.ok,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
dialog.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
alert.setCancelable(true);
|
||||||
|
|
||||||
|
return alert.create();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui.dialog;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Id;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.util.Choice;
|
||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
public class CreateKeyDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
|
public interface OnAlgorithmSelectedListener {
|
||||||
|
public void onAlgorithmSelected(Choice algorithmChoice, int keySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String ARG_EDITOR_CHILD_COUNT = "child_count";
|
||||||
|
|
||||||
|
private int mNewKeySize;
|
||||||
|
private Choice mNewKeyAlgorithmChoice;
|
||||||
|
private OnAlgorithmSelectedListener mAlgorithmSelectedListener;
|
||||||
|
|
||||||
|
public void setOnAlgorithmSelectedListener(OnAlgorithmSelectedListener listener) {
|
||||||
|
mAlgorithmSelectedListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CreateKeyDialogFragment newInstance(int mEditorChildCount) {
|
||||||
|
CreateKeyDialogFragment frag = new CreateKeyDialogFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
|
||||||
|
args.putInt(ARG_EDITOR_CHILD_COUNT, mEditorChildCount);
|
||||||
|
|
||||||
|
frag.setArguments(args);
|
||||||
|
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final FragmentActivity context = getActivity();
|
||||||
|
final LayoutInflater mInflater;
|
||||||
|
|
||||||
|
final int childCount = getArguments().getInt(ARG_EDITOR_CHILD_COUNT);
|
||||||
|
mInflater = context.getLayoutInflater();
|
||||||
|
|
||||||
|
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
|
||||||
|
|
||||||
|
View view = mInflater.inflate(R.layout.create_key_dialog, null);
|
||||||
|
dialog.setView(view);
|
||||||
|
dialog.setTitle(R.string.title_create_key);
|
||||||
|
|
||||||
|
boolean wouldBeMasterKey = (childCount == 0);
|
||||||
|
|
||||||
|
final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm);
|
||||||
|
Vector<Choice> choices = new Vector<Choice>();
|
||||||
|
choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString(
|
||||||
|
R.string.dsa)));
|
||||||
|
if (!wouldBeMasterKey) {
|
||||||
|
choices.add(new Choice(Id.choice.algorithm.elgamal, getResources().getString(
|
||||||
|
R.string.elgamal)));
|
||||||
|
}
|
||||||
|
|
||||||
|
choices.add(new Choice(Id.choice.algorithm.rsa, getResources().getString(
|
||||||
|
R.string.rsa)));
|
||||||
|
|
||||||
|
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(context,
|
||||||
|
android.R.layout.simple_spinner_item, choices);
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
algorithm.setAdapter(adapter);
|
||||||
|
// make RSA the default
|
||||||
|
for (int i = 0; i < choices.size(); ++i) {
|
||||||
|
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
|
||||||
|
algorithm.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size);
|
||||||
|
ArrayAdapter<CharSequence> keySizeAdapter = ArrayAdapter.createFromResource(
|
||||||
|
context, R.array.key_size_spinner_values,
|
||||||
|
android.R.layout.simple_spinner_item);
|
||||||
|
keySizeAdapter
|
||||||
|
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
keySize.setAdapter(keySizeAdapter);
|
||||||
|
keySize.setSelection(3); // Default to 4096 for the key length
|
||||||
|
dialog.setPositiveButton(android.R.string.ok,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface di, int id) {
|
||||||
|
di.dismiss();
|
||||||
|
try {
|
||||||
|
int nKeyIndex = keySize.getSelectedItemPosition();
|
||||||
|
switch (nKeyIndex) {
|
||||||
|
case 0:
|
||||||
|
mNewKeySize = 512;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mNewKeySize = 1024;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mNewKeySize = 2048;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mNewKeySize = 4096;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
mNewKeySize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
|
||||||
|
mAlgorithmSelectedListener.onAlgorithmSelected(mNewKeyAlgorithmChoice, mNewKeySize);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.setCancelable(true);
|
||||||
|
dialog.setNegativeButton(android.R.string.cancel,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface di, int id) {
|
||||||
|
di.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return dialog.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -61,7 +61,8 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
||||||
|
|
||||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
|
||||||
|
alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
||||||
alert.setTitle(R.string.warning);
|
alert.setTitle(R.string.warning);
|
||||||
alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile));
|
alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile));
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ public class DeleteFileDialogFragment extends DialogFragment {
|
|||||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
|
|
||||||
ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance(
|
ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance(
|
||||||
R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL);
|
R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL, false, null);
|
||||||
|
|
||||||
// Message is received after deleting is done in ApgService
|
// Message is received after deleting is done in ApgService
|
||||||
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) {
|
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) {
|
||||||
|
@ -17,17 +17,6 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui.dialog;
|
package org.sufficientlysecure.keychain.ui.dialog;
|
||||||
|
|
||||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
|
||||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
|
||||||
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.provider.KeychainContract;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@ -40,6 +29,14 @@ import android.os.RemoteException;
|
|||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.Id;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class DeleteKeyDialogFragment extends DialogFragment {
|
public class DeleteKeyDialogFragment extends DialogFragment {
|
||||||
@ -100,7 +97,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
builder.setMessage(R.string.key_deletion_confirmation_multi);
|
builder.setMessage(R.string.key_deletion_confirmation_multi);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
builder.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
||||||
builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -153,7 +153,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
|
|||||||
dismiss();
|
dismiss();
|
||||||
long curKeyIndex = 1;
|
long curKeyIndex = 1;
|
||||||
boolean keyOK = true;
|
boolean keyOK = true;
|
||||||
String passPhrase = mPassphraseEditText.getText().toString();
|
String passphrase = mPassphraseEditText.getText().toString();
|
||||||
long keyId;
|
long keyId;
|
||||||
PGPSecretKey clickSecretKey = secretKey;
|
PGPSecretKey clickSecretKey = secretKey;
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
|
|||||||
try {
|
try {
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||||
passPhrase.toCharArray());
|
passphrase.toCharArray());
|
||||||
PGPPrivateKey testKey = clickSecretKey
|
PGPPrivateKey testKey = clickSecretKey
|
||||||
.extractPrivateKey(keyDecryptor);
|
.extractPrivateKey(keyDecryptor);
|
||||||
if (testKey == null) {
|
if (testKey == null) {
|
||||||
@ -206,10 +206,10 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
|
|||||||
|
|
||||||
// cache the new passphrase
|
// cache the new passphrase
|
||||||
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
|
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
|
||||||
PassphraseCacheService.addCachedPassphrase(activity, keyId, passPhrase);
|
PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase);
|
||||||
if (keyOK == false && clickSecretKey.getKeyID() != keyId) {
|
if (keyOK == false && clickSecretKey.getKeyID() != keyId) {
|
||||||
PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(),
|
PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(),
|
||||||
passPhrase);
|
passphrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessageToHandler(MESSAGE_OKAY);
|
sendMessageToHandler(MESSAGE_OKAY);
|
||||||
|
@ -21,28 +21,40 @@ import android.app.Activity;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
import android.content.DialogInterface.OnKeyListener;
|
import android.content.DialogInterface.OnKeyListener;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
|
||||||
public class ProgressDialogFragment extends DialogFragment {
|
public class ProgressDialogFragment extends DialogFragment {
|
||||||
private static final String ARG_MESSAGE_ID = "message_id";
|
private static final String ARG_MESSAGE_ID = "message_id";
|
||||||
private static final String ARG_STYLE = "style";
|
private static final String ARG_STYLE = "style";
|
||||||
|
private static final String ARG_CANCELABLE = "cancelable";
|
||||||
|
|
||||||
|
private OnCancelListener mOnCancelListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*
|
*
|
||||||
* @param id
|
* @param messageId
|
||||||
|
* @param style
|
||||||
|
* @param cancelable
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static ProgressDialogFragment newInstance(int messageId, int style) {
|
public static ProgressDialogFragment newInstance(int messageId, int style, boolean cancelable,
|
||||||
|
OnCancelListener onCancelListener) {
|
||||||
ProgressDialogFragment frag = new ProgressDialogFragment();
|
ProgressDialogFragment frag = new ProgressDialogFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt(ARG_MESSAGE_ID, messageId);
|
args.putInt(ARG_MESSAGE_ID, messageId);
|
||||||
args.putInt(ARG_STYLE, style);
|
args.putInt(ARG_STYLE, style);
|
||||||
|
args.putBoolean(ARG_CANCELABLE, cancelable);
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
frag.mOnCancelListener = onCancelListener;
|
||||||
|
|
||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +72,6 @@ public class ProgressDialogFragment extends DialogFragment {
|
|||||||
/**
|
/**
|
||||||
* Updates progress of dialog
|
* Updates progress of dialog
|
||||||
*
|
*
|
||||||
* @param messageId
|
|
||||||
* @param progress
|
* @param progress
|
||||||
* @param max
|
* @param max
|
||||||
*/
|
*/
|
||||||
@ -74,7 +85,7 @@ public class ProgressDialogFragment extends DialogFragment {
|
|||||||
/**
|
/**
|
||||||
* Updates progress of dialog
|
* Updates progress of dialog
|
||||||
*
|
*
|
||||||
* @param messageId
|
* @param message
|
||||||
* @param progress
|
* @param progress
|
||||||
* @param max
|
* @param max
|
||||||
*/
|
*/
|
||||||
@ -86,12 +97,20 @@ public class ProgressDialogFragment extends DialogFragment {
|
|||||||
dialog.setMax(max);
|
dialog.setMax(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
super.onCancel(dialog);
|
||||||
|
|
||||||
|
if (this.mOnCancelListener != null)
|
||||||
|
this.mOnCancelListener.onCancel(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates dialog
|
* Creates dialog
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
|
|
||||||
ProgressDialog dialog = new ProgressDialog(activity);
|
ProgressDialog dialog = new ProgressDialog(activity);
|
||||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
@ -100,10 +119,22 @@ public class ProgressDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
int messageId = getArguments().getInt(ARG_MESSAGE_ID);
|
int messageId = getArguments().getInt(ARG_MESSAGE_ID);
|
||||||
int style = getArguments().getInt(ARG_STYLE);
|
int style = getArguments().getInt(ARG_STYLE);
|
||||||
|
boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE);
|
||||||
|
|
||||||
dialog.setMessage(getString(messageId));
|
dialog.setMessage(getString(messageId));
|
||||||
dialog.setProgressStyle(style);
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Disable the back button
|
// Disable the back button
|
||||||
OnKeyListener keyListener = new OnKeyListener() {
|
OnKeyListener keyListener = new OnKeyListener() {
|
||||||
|
|
||||||
|
@ -101,9 +101,9 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
|
|||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
dismiss();
|
dismiss();
|
||||||
|
|
||||||
String passPhrase1 = mPassphraseEditText.getText().toString();
|
String passphrase1 = mPassphraseEditText.getText().toString();
|
||||||
String passPhrase2 = mPassphraseAgainEditText.getText().toString();
|
String passphrase2 = mPassphraseAgainEditText.getText().toString();
|
||||||
if (!passPhrase1.equals(passPhrase2)) {
|
if (!passphrase1.equals(passphrase2)) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
activity,
|
activity,
|
||||||
getString(R.string.error_message,
|
getString(R.string.error_message,
|
||||||
@ -112,7 +112,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passPhrase1.equals("")) {
|
if (passphrase1.equals("")) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
activity,
|
activity,
|
||||||
getString(R.string.error_message,
|
getString(R.string.error_message,
|
||||||
@ -123,7 +123,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
|
|||||||
|
|
||||||
// return resulting data back to activity
|
// return resulting data back to activity
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
data.putString(MESSAGE_NEW_PASSPHRASE, passPhrase1);
|
data.putString(MESSAGE_NEW_PASSPHRASE, passphrase1);
|
||||||
|
|
||||||
sendMessageToHandler(MESSAGE_OKAY, data);
|
sendMessageToHandler(MESSAGE_OKAY, data);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ public class ShareNfcDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
||||||
|
|
||||||
alert.setIcon(android.R.drawable.ic_dialog_info);
|
|
||||||
alert.setTitle(R.string.share_nfc_dialog);
|
alert.setTitle(R.string.share_nfc_dialog);
|
||||||
alert.setCancelable(true);
|
alert.setCancelable(true);
|
||||||
|
|
||||||
|
@ -17,28 +17,26 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui.dialog;
|
package org.sufficientlysecure.keychain.ui.dialog;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
import org.sufficientlysecure.keychain.util.QrCodeUtils;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.ContextThemeWrapper;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.util.QrCodeUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class ShareQrCodeDialogFragment extends DialogFragment {
|
public class ShareQrCodeDialogFragment extends DialogFragment {
|
||||||
private static final String ARG_KEY_URI = "uri";
|
private static final String ARG_KEY_URI = "uri";
|
||||||
private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only";
|
private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only";
|
||||||
|
@ -35,6 +35,7 @@ import android.app.DatePickerDialog;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
@ -60,6 +61,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
|||||||
TextView mKeyId;
|
TextView mKeyId;
|
||||||
TextView mCreationDate;
|
TextView mCreationDate;
|
||||||
BootstrapButton mExpiryDateButton;
|
BootstrapButton mExpiryDateButton;
|
||||||
|
GregorianCalendar mCreatedDate;
|
||||||
GregorianCalendar mExpiryDate;
|
GregorianCalendar mExpiryDate;
|
||||||
GregorianCalendar mOriginalExpiryDate = null;
|
GregorianCalendar mOriginalExpiryDate = null;
|
||||||
CheckBox mChkCertify;
|
CheckBox mChkCertify;
|
||||||
@ -142,8 +144,12 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
|||||||
if (date == null) {
|
if (date == null) {
|
||||||
date = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
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),
|
mExpiryDateSetListener, date.get(Calendar.YEAR), date.get(Calendar.MONTH),
|
||||||
date.get(Calendar.DAY_OF_MONTH));
|
date.get(Calendar.DAY_OF_MONTH));
|
||||||
mDatePickerResultCount = 0;
|
mDatePickerResultCount = 0;
|
||||||
@ -161,6 +167,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();
|
dialog.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -237,7 +258,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
|||||||
|
|
||||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||||
cal.setTime(PgpKeyHelper.getCreationDate(key));
|
cal.setTime(PgpKeyHelper.getCreationDate(key));
|
||||||
mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime()));
|
setCreatedDate(cal);
|
||||||
cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||||
Date expiryDate = PgpKeyHelper.getExpiryDate(key);
|
Date expiryDate = PgpKeyHelper.getExpiryDate(key);
|
||||||
if (expiryDate == null) {
|
if (expiryDate == null) {
|
||||||
@ -268,6 +289,15 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
|
|||||||
mEditorListener = listener;
|
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) {
|
private void setExpiryDate(GregorianCalendar date) {
|
||||||
mExpiryDate = date;
|
mExpiryDate = date;
|
||||||
if (date == null) {
|
if (date == null) {
|
||||||
@ -320,3 +350,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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -46,13 +46,25 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||||
|
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.sufficientlysecure.keychain.Id;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.CreateKeyDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
|
||||||
|
import org.sufficientlysecure.keychain.util.Choice;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Editor {
|
public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Editor {
|
||||||
private LayoutInflater mInflater;
|
private LayoutInflater mInflater;
|
||||||
private BootstrapButton mPlusButton;
|
private BootstrapButton mPlusButton;
|
||||||
@ -252,84 +264,16 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Id.type.key: {
|
case Id.type.key: {
|
||||||
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
|
CreateKeyDialogFragment mCreateKeyDialogFragment = CreateKeyDialogFragment.newInstance(mEditors.getChildCount());
|
||||||
|
mCreateKeyDialogFragment.setOnAlgorithmSelectedListener(new CreateKeyDialogFragment.OnAlgorithmSelectedListener() {
|
||||||
View view = mInflater.inflate(R.layout.create_key_dialog, null);
|
@Override
|
||||||
dialog.setView(view);
|
public void onAlgorithmSelected(Choice algorithmChoice, int keySize) {
|
||||||
dialog.setTitle(R.string.title_create_key);
|
mNewKeyAlgorithmChoice = algorithmChoice;
|
||||||
|
mNewKeySize = keySize;
|
||||||
boolean wouldBeMasterKey = (mEditors.getChildCount() == 0);
|
createKey();
|
||||||
|
|
||||||
final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm);
|
|
||||||
Vector<Choice> choices = new Vector<Choice>();
|
|
||||||
choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString(
|
|
||||||
R.string.dsa)));
|
|
||||||
if (!wouldBeMasterKey) {
|
|
||||||
choices.add(new Choice(Id.choice.algorithm.elgamal, getResources().getString(
|
|
||||||
R.string.elgamal)));
|
|
||||||
}
|
|
||||||
|
|
||||||
choices.add(new Choice(Id.choice.algorithm.rsa, getResources().getString(
|
|
||||||
R.string.rsa)));
|
|
||||||
|
|
||||||
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getContext(),
|
|
||||||
android.R.layout.simple_spinner_item, choices);
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
algorithm.setAdapter(adapter);
|
|
||||||
// make RSA the default
|
|
||||||
for (int i = 0; i < choices.size(); ++i) {
|
|
||||||
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
|
|
||||||
algorithm.setSelection(i);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog");
|
||||||
final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size);
|
|
||||||
ArrayAdapter<CharSequence> keySizeAdapter = ArrayAdapter.createFromResource(
|
|
||||||
getContext(), R.array.key_size_spinner_values,
|
|
||||||
android.R.layout.simple_spinner_item);
|
|
||||||
keySizeAdapter
|
|
||||||
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
keySize.setAdapter(keySizeAdapter);
|
|
||||||
keySize.setSelection(3); // Default to 4096 for the key length
|
|
||||||
dialog.setPositiveButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface di, int id) {
|
|
||||||
di.dismiss();
|
|
||||||
try {
|
|
||||||
int nKeyIndex = keySize.getSelectedItemPosition();
|
|
||||||
switch (nKeyIndex) {
|
|
||||||
case 0:
|
|
||||||
mNewKeySize = 512;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
mNewKeySize = 1024;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mNewKeySize = 2048;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mNewKeySize = 4096;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
mNewKeySize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
|
|
||||||
createKey();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog.setCancelable(true);
|
|
||||||
dialog.setNegativeButton(android.R.string.cancel,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface di, int id) {
|
|
||||||
di.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog.create().show();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,7 +326,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
|||||||
|
|
||||||
private void createKey() {
|
private void createKey() {
|
||||||
// Send all information needed to service to edit key in other thread
|
// Send all information needed to service to edit key in other thread
|
||||||
Intent intent = new Intent(mActivity, KeychainIntentService.class);
|
final Intent intent = new Intent(mActivity, KeychainIntentService.class);
|
||||||
|
|
||||||
intent.setAction(KeychainIntentService.ACTION_GENERATE_KEY);
|
intent.setAction(KeychainIntentService.ACTION_GENERATE_KEY);
|
||||||
|
|
||||||
@ -390,18 +334,18 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
|||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
Boolean isMasterKey;
|
Boolean isMasterKey;
|
||||||
|
|
||||||
String passPhrase;
|
String passphrase;
|
||||||
if (mEditors.getChildCount() > 0) {
|
if (mEditors.getChildCount() > 0) {
|
||||||
PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
|
PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
|
||||||
passPhrase = PassphraseCacheService
|
passphrase = PassphraseCacheService
|
||||||
.getCachedPassphrase(mActivity, masterKey.getKeyID());
|
.getCachedPassphrase(mActivity, masterKey.getKeyID());
|
||||||
isMasterKey = false;
|
isMasterKey = false;
|
||||||
} else {
|
} else {
|
||||||
passPhrase = "";
|
passphrase = "";
|
||||||
isMasterKey = true;
|
isMasterKey = true;
|
||||||
}
|
}
|
||||||
data.putBoolean(KeychainIntentService.GENERATE_KEY_MASTER_KEY, isMasterKey);
|
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_ALGORITHM, mNewKeyAlgorithmChoice.getId());
|
||||||
data.putInt(KeychainIntentService.GENERATE_KEY_KEY_SIZE, mNewKeySize);
|
data.putInt(KeychainIntentService.GENERATE_KEY_KEY_SIZE, mNewKeySize);
|
||||||
|
|
||||||
@ -409,7 +353,12 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
|||||||
|
|
||||||
// show progress dialog
|
// show progress dialog
|
||||||
mGeneratingDialog = ProgressDialogFragment.newInstance(R.string.progress_generating,
|
mGeneratingDialog = ProgressDialogFragment.newInstance(R.string.progress_generating,
|
||||||
ProgressDialog.STYLE_SPINNER);
|
ProgressDialog.STYLE_SPINNER, true, new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
mActivity.stopService(intent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Message is received after generating is done in ApgService
|
// Message is received after generating is done in ApgService
|
||||||
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity,
|
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2011 Thialfihar <thi@thialfihar.org>
|
||||||
* Copyright (C) 2011 Senecaso
|
* Copyright (C) 2011 Senecaso
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -32,6 +34,7 @@ import java.util.List;
|
|||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
@ -172,11 +175,11 @@ public class HkpKeyServer extends KeyServer {
|
|||||||
if (e.getCode() == 404) {
|
if (e.getCode() == 404) {
|
||||||
return results;
|
return results;
|
||||||
} else {
|
} else {
|
||||||
if (e.getData().toLowerCase().contains("no keys found")) {
|
if (e.getData().toLowerCase(Locale.US).contains("no keys found")) {
|
||||||
return results;
|
return results;
|
||||||
} else if (e.getData().toLowerCase().contains("too many")) {
|
} else if (e.getData().toLowerCase(Locale.US).contains("too many")) {
|
||||||
throw new TooManyResponses();
|
throw new TooManyResponses();
|
||||||
} else if (e.getData().toLowerCase().contains("insufficient")) {
|
} else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) {
|
||||||
throw new InsufficientQuery();
|
throw new InsufficientQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2011 Thialfihar <thi@thialfihar.org>
|
||||||
* Copyright (C) 2011 Senecaso
|
* Copyright (C) 2011 Senecaso
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -16,14 +18,8 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.util;
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||||
|
|
||||||
public abstract class KeyServer {
|
public abstract class KeyServer {
|
||||||
@ -52,5 +48,5 @@ public abstract class KeyServer {
|
|||||||
|
|
||||||
abstract String get(long keyId) throws QueryException;
|
abstract String get(long keyId) throws QueryException;
|
||||||
|
|
||||||
abstract void add(String armouredText) throws AddKeyException;
|
abstract void add(String armoredText) throws AddKeyException;
|
||||||
}
|
}
|
||||||
|
BIN
OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_search.png
Normal file
After Width: | Height: | Size: 702 B |
BIN
OpenPGP-Keychain/src/main/res/drawable-hdpi/ic_action_secure.png
Normal file
After Width: | Height: | Size: 394 B |
After Width: | Height: | Size: 507 B |
After Width: | Height: | Size: 1018 B |
BIN
OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_search.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
OpenPGP-Keychain/src/main/res/drawable-mdpi/ic_action_secure.png
Normal file
After Width: | Height: | Size: 317 B |
After Width: | Height: | Size: 292 B |
After Width: | Height: | Size: 770 B |
After Width: | Height: | Size: 900 B |
After Width: | Height: | Size: 510 B |
After Width: | Height: | Size: 351 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 563 B |
After Width: | Height: | Size: 1.9 KiB |
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
@ -26,4 +26,4 @@
|
|||||||
tools:layout="@layout/api_app_settings_fragment" />
|
tools:layout="@layout/api_app_settings_fragment" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
@ -18,4 +18,4 @@
|
|||||||
tools:layout="@layout/api_app_settings_fragment" />
|
tools:layout="@layout/api_app_settings_fragment" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
android:text="@string/label_no_passphrase" />
|
android:text="@string/label_no_passphrase" />
|
||||||
|
|
||||||
<com.beardedhen.androidbootstrap.BootstrapButton
|
<com.beardedhen.androidbootstrap.BootstrapButton
|
||||||
android:id="@+id/edit_key_btn_change_pass_phrase"
|
android:id="@+id/edit_key_btn_change_passphrase"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
|
@ -135,7 +135,7 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/label_passPhrase"
|
android:id="@+id/label_passphrase"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
@ -144,7 +144,7 @@
|
|||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/passPhrase"
|
android:id="@+id/passphrase"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="textPassword" />
|
android:inputType="textPassword" />
|
||||||
@ -153,7 +153,7 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/label_passPhraseAgain"
|
android:id="@+id/label_passphraseAgain"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
@ -162,7 +162,7 @@
|
|||||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/passPhraseAgain"
|
android:id="@+id/passphraseAgain"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="textPassword" />
|
android:inputType="textPassword" />
|
||||||
|
@ -71,8 +71,8 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/editors"
|
android:id="@+id/editors"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical" />
|
android:orientation="vertical" />
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -4,8 +4,16 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerHorizontal="true" >
|
android:layout_centerHorizontal="true" >
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/select_public_key_search"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/menu_search"
|
||||||
|
android:drawableLeft="@drawable/ic_action_search"/>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/select_public_key_fragment_container"
|
android:id="@+id/select_public_key_fragment_container"
|
||||||
|
android:layout_below="@id/select_public_key_search"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
@ -11,5 +11,10 @@
|
|||||||
android:id="@+id/menu_key_list_public_export"
|
android:id="@+id/menu_key_list_public_export"
|
||||||
app:showAsAction="never"
|
app:showAsAction="never"
|
||||||
android:title="@string/menu_export_keys" />
|
android:title="@string/menu_export_keys" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_key_list_public_search"
|
||||||
|
android:title="@string/menu_search"
|
||||||
|
android:icon="@drawable/ic_action_search"
|
||||||
|
app:actionViewClass="android.support.v7.widget.SearchView"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
</menu>
|
</menu>
|
@ -1,8 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_key_list_public_multi_select_all"
|
||||||
|
android:icon="@drawable/ic_action_select_all"
|
||||||
|
android:title="@string/menu_select_all" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_key_list_public_multi_encrypt"
|
android:id="@+id/menu_key_list_public_multi_encrypt"
|
||||||
|
android:icon="@drawable/ic_action_secure"
|
||||||
android:title="@string/menu_encrypt_to" />
|
android:title="@string/menu_encrypt_to" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_key_list_public_multi_delete"
|
android:id="@+id/menu_key_list_public_multi_delete"
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_key_list_public_multi_select_all"
|
||||||
|
android:icon="@drawable/ic_action_select_all"
|
||||||
|
android:title="@string/menu_select_all" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_key_list_public_multi_delete"
|
android:id="@+id/menu_key_list_public_multi_delete"
|
||||||
android:icon="@drawable/ic_action_discard"
|
android:icon="@drawable/ic_action_discard"
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
<body>
|
<body>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
|
<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> ist eine OpenPGP-Implementierung für Android. Die Entwicklung begann als ein Fork von Android Privacy Guard (APG).</p>
|
<p><a href="http://www.openkeychain.org">OpenKeychain</a> ist eine OpenPGP implementation für Android.</p>
|
||||||
<p>Lizenz: GPLv3+</p>
|
<p>Lizenz: GPLv3+</p>
|
||||||
|
|
||||||
<h2>Entwickler OpenPGP Keychain</h2>
|
<h2>Entwickler OpenKeychain</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Dominik Schürmann (Leitender Entwickler)</li>
|
<li>Dominik Schürmann (Leitender Entwickler)</li>
|
||||||
<li>Ash Hughes (crypto patches)</li>
|
<li>Ash Hughes (crypto patches)</li>
|
||||||
@ -23,9 +23,9 @@
|
|||||||
<h2>Bibliotheken</h2>
|
<h2>Bibliotheken</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Bibliothek v4</a> (Apache Lizenz v2)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Bibliothek v7 'appcompat'</a> (Apache Lizenz v2)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Lizenz v2)</li>
|
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Lizenz v2)</li>
|
||||||
<li>
|
<li>
|
||||||
@ -36,6 +36,8 @@
|
|||||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Lizenz)</li>
|
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Lizenz)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache Lizenz v2)</li>
|
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache Lizenz v2)</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Bibliothek</a> (Apache Lizenz v2)</li>
|
||||||
<li>Icons von <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike Lizenz 3.0)</li>
|
<li>Icons von <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike Lizenz 3.0)</li>
|
||||||
<li>Icons von <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
|
<li>Icons von <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
<h2>2.2</h2>
|
<h2>2.2</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>new design with navigation drawer</li>
|
<li>new design with navigation drawer</li>
|
||||||
<li>new public key list design</li>
|
<li>Neus Design für die Liste der öffentlichen Schlüssel</li>
|
||||||
<li>new public key view</li>
|
<li>new public key view</li>
|
||||||
<li>bug fixes for importing of keys</li>
|
<li>Fehler beim Schlüsselimport behoben</li>
|
||||||
<li>key cross-certification (thanks to Ash Hughes)</li>
|
<li>key cross-certification (thanks to Ash Hughes)</li>
|
||||||
<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
|
<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
|
||||||
<li>first version with new languages (thanks to the contributors on Transifex)</li>
|
<li>Erste Version mit neuen Sprachen (Danke an die Mitwirkenden bei Transifex)</li>
|
||||||
<li>sharing of keys via QR Codes fixed and improved</li>
|
<li>sharing of keys via QR Codes fixed and improved</li>
|
||||||
<li>package signature verification for API</li>
|
<li>package signature verification for API</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -31,16 +31,16 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<h2>2.1</h2>
|
<h2>2.1</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>lots of bug fixes</li>
|
<li>Viele Fehler behoben</li>
|
||||||
<li>new API for developers</li>
|
<li>Neue API für Entwickler</li>
|
||||||
<li>PRNG bug fix by Google</li>
|
<li>PRNG Bugfix von Google</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>2.0</h2>
|
<h2>2.0</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>complete redesign</li>
|
<li>Komlett neu designd</li>
|
||||||
<li>share public keys via qr codes, nfc beam</li>
|
<li>share public keys via qr codes, nfc beam</li>
|
||||||
<li>sign keys</li>
|
<li>Schlüssel signieren</li>
|
||||||
<li>upload keys to server</li>
|
<li>Schlüssel auf den Server hochladen</li>
|
||||||
<li>fixes import issues</li>
|
<li>fixes import issues</li>
|
||||||
<li>new AIDL API</li>
|
<li>new AIDL API</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -56,25 +56,25 @@
|
|||||||
<h2>1.0.7</h2>
|
<h2>1.0.7</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>fixed problem with signature verification of texts with trailing newline</li>
|
<li>fixed problem with signature verification of texts with trailing newline</li>
|
||||||
<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li>
|
<li>weitere Optionen für die Time-to-live des Passphrasencaches (20, 40, 60 mins)</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.6</h2>
|
<h2>1.0.6</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>account adding crash on Froyo fixed</li>
|
<li>crash beim Hinzufügen eines Kontos auf Froyo repariert</li>
|
||||||
<li>sichere Dateilöschung</li>
|
<li>sichere Dateilöschung</li>
|
||||||
<li>option to delete key file after import</li>
|
<li>Option, um Schlüsseldatei nach dem Import zu löschen</li>
|
||||||
<li>Streamverschlüsselung/-entschlüsselung (Galerie, etc.)</li>
|
<li>Streamverschlüsselung/-entschlüsselung (Galerie, etc.)</li>
|
||||||
<li>new options (language, force v3 signatures)</li>
|
<li>neue Optionen (Sprache, v3-Unterschriften erzwingen)</li>
|
||||||
<li>interface changes</li>
|
<li>Interfaceänderungen</li>
|
||||||
<li>Fehlerbehebungen</li>
|
<li>Fehlerbehebungen</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.5</h2>
|
<h2>1.0.5</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Deutsche und Italienische Übersetzung</li>
|
<li>Deutsche und Italienische Übersetzung</li>
|
||||||
<li>much smaller package, due to reduced BC sources</li>
|
<li>viel kleineres Paket, dank reduzierter BC Quellen</li>
|
||||||
<li>new preferences GUI</li>
|
<li>Neues Einstellungs-GUI</li>
|
||||||
<li>layout adjustment for localization</li>
|
<li>Lay-Out-Anpassung für die Lokalisierung</li>
|
||||||
<li>signature bugfix</li>
|
<li>Fehler bei Signatur behoben</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.4</h2>
|
<h2>1.0.4</h2>
|
||||||
<ul>
|
<ul>
|
||||||
@ -82,11 +82,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.3</h2>
|
<h2>1.0.3</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>fixed crashes during encryption/signing and possibly key export</li>
|
<li>Absturz während der Verschlüsselung/Signierung und möglicherweise Schlüsselexport behoben.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.2</h2>
|
<h2>1.0.2</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>filterable key lists</li>
|
<li>Filterbare Schlüsselliste</li>
|
||||||
<li>smarter pre-selection of encryption keys</li>
|
<li>smarter pre-selection of encryption keys</li>
|
||||||
<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
|
<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
|
||||||
<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
|
<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
|
||||||
@ -100,7 +100,7 @@
|
|||||||
<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
|
<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
|
||||||
<li>support of more file managers (including ASTRO)</li>
|
<li>support of more file managers (including ASTRO)</li>
|
||||||
<li>Slovenian translation</li>
|
<li>Slovenian translation</li>
|
||||||
<li>new database, much faster, less memory usage</li>
|
<li>Neue Datenbank, viel schneller, weniger Speicherbedarf</li>
|
||||||
<li>defined Intents and content provider for other apps</li>
|
<li>defined Intents and content provider for other apps</li>
|
||||||
<li>Fehlerbehebungen</li>
|
<li>Fehlerbehebungen</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
|
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
|
||||||
|
|
||||||
<h2>I found a bug in OpenPGP Keychain!</h2>
|
<h2>Ich habe einen Fehler in OpenKeychain gefunden!</h2>
|
||||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
|
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||||
|
|
||||||
<h2>Contribute</h2>
|
<h2>Contribute</h2>
|
||||||
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
|
<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
|
||||||
|
|
||||||
<h2>Translations</h2>
|
<h2>Übersetzungen</h2>
|
||||||
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
|
<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
<body>
|
<body>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
|
<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p>
|
<p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
|
||||||
<p>License: GPLv3+</p>
|
<p>License: GPLv3+</p>
|
||||||
|
|
||||||
<h2>Developers OpenPGP Keychain</h2>
|
<h2>Developers OpenKeychain</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Dominik Schürmann (Lead developer)</li>
|
<li>Dominik Schürmann (Lead developer)</li>
|
||||||
<li>Ash Hughes (crypto patches)</li>
|
<li>Ash Hughes (crypto patches)</li>
|
||||||
@ -36,6 +36,8 @@
|
|||||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
|
||||||
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
|
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
|
||||||
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
|
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
|
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
|
||||||
|
|
||||||
<h2>I found a bug in OpenPGP Keychain!</h2>
|
<h2>I found a bug in OpenKeychain!</h2>
|
||||||
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p>
|
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
|
||||||
|
|
||||||
<h2>Contribute</h2>
|
<h2>Contribute</h2>
|
||||||
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
|
<p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
|
||||||
|
|
||||||
<h2>Translations</h2>
|
<h2>Translations</h2>
|
||||||
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p>
|
<p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
<body>
|
<body>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
|
<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> es una implementación de OpenPGP para Android. Su desarrollo comenzó como un fork de Android Privacy Guard (APG).</p>
|
<p><a href="http://www.openkeychain.org">OpenKeychain</a> es una implementación de OpenPGP para Android.</p>
|
||||||
<p>Licencia: GPLv3+</p>
|
<p>Licencia: GPLv3+</p>
|
||||||
|
|
||||||
<h2>Desarrolladores de OpenPGP Keychain</h2>
|
<h2>Desarrolladores OpenKeychain</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Dominik Schürmann (Desarrollador principal)</li>
|
<li>Dominik Schürmann (Desarrollador principal)</li>
|
||||||
<li>Ash Hughes (Parches cryptográficos)</li>
|
<li>Ash Hughes (Parches cryptográficos)</li>
|
||||||
@ -36,6 +36,8 @@
|
|||||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencia MIT X11)</li>
|
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencia MIT X11)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencia Apache v2)</li>
|
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencia Apache v2)</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/johnkil/Android-AppMsg">Librería Android AppMsg</a> (Licencia Apache v2)</li>
|
||||||
<li>Icons de <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Compartir-Igual licencia 3.0)</li>
|
<li>Icons de <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Compartir-Igual licencia 3.0)</li>
|
||||||
<li>Iconos de <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Dominio Público)</li>
|
<li>Iconos de <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Dominio Público)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
<p>Es recomendable que instales <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> para una mejor selección de archivos y <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> para escanear los códigos QR generados. Pulsando en los enlaces se abrirá Google Play o F-Droid.</p>
|
<p>Es recomendable que instales <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> para una mejor selección de archivos y <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> para escanear los códigos QR generados. Pulsando en los enlaces se abrirá Google Play o F-Droid.</p>
|
||||||
|
|
||||||
<h2>¡He encontrado un bug en OpenPGP Keychain!</h2>
|
<h2>¡He encontrado un bug en OpenKeychain!</h2>
|
||||||
<p>Por favor, informa de errores usando el <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">seguimiento de incidencias de OpenPGP Keychain</a>.</p>
|
<p>Por favor, informa de errores usando el <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">seguimiento de incidencias de OpenKeychain</a>.</p>
|
||||||
|
|
||||||
<h2>Aportar</h2>
|
<h2>Aportar</h2>
|
||||||
<p>Si quieres ayudarnos con el desarrollo de OpenPGP Keychain aportando código <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">sigue nuestra pequeña guía en Github</a>.</p>
|
<p>Si quieres ayudarnos con el desarrollo de OpenKeychain aportando código <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">sigue nuestra pequeña guía en Github</a>.</p>
|
||||||
|
|
||||||
<h2>Traducciones</h2>
|
<h2>Traducciones</h2>
|
||||||
<p>¡Ayúdanos a traducir OpenPGP Keychain! Todo el mundo es bienvenido en <a href="https://www.transifex.com/projects/p/openpgp-keychain/">Transifex - OpenPGP Keychain</a>.</p>
|
<p>¡Ayúdanos a traducir OpenKeychain! Todo el mundo es bienvenido en <a href="https://www.transifex.com/projects/p/openpgp-keychain/">Transifex - OpenKeychain</a>.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
<body>
|
<body>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
|
<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">Le porte-clefs OpenPGP</a> est une implémentation d'OpenPGP pour Android. Le développement a commencé comme bifurcation d'Android Privacy Guard (APG).</p>
|
<p><a href="http://www.openkeychain.org">OpenKeychain</a> est une implémentation d'OpenPGP pour Android.</p>
|
||||||
<p>Licence : GPLv3+</p>
|
<p>Licence : GPLv3+</p>
|
||||||
|
|
||||||
<h2>Les développeurs du Porte-clefs OpenPGP</h2>
|
<h2>Les développeurs d'OpenKeychain</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Dominik Schürmann (développeur principal)</li>
|
<li>Dominik Schürmann (développeur principal)</li>
|
||||||
<li>Ash Hughes (correctif crypto)</li>
|
<li>Ash Hughes (correctif crypto)</li>
|
||||||
@ -36,6 +36,8 @@
|
|||||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licence MIT X11)</li>
|
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licence MIT X11)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licence Apache v2)</li>
|
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licence Apache v2)</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/johnkil/Android-AppMsg">Bibliothèque Android AppMsg</a> (Licence Apache v2)</li>
|
||||||
<li>Icônes du <a href="http://rrze-icon-set.berlios.de/">jeu d'icônes RRZE</a> (Licence Creative Commons Paternité - Partage des Conditions Initiales à l'Identique 3.0)</li>
|
<li>Icônes du <a href="http://rrze-icon-set.berlios.de/">jeu d'icônes RRZE</a> (Licence Creative Commons Paternité - Partage des Conditions Initiales à l'Identique 3.0)</li>
|
||||||
<li>Icônes du <a href="http://tango.freedesktop.org/">jeu d'icônes Tango</a> (domaine public)</li>
|
<li>Icônes du <a href="http://tango.freedesktop.org/">jeu d'icônes Tango</a> (domaine public)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
<p>Il vous est recommendé d'installer le <a href="market://details?id=org.openintents.filemanager">gestionnaire de fichiers OI</a> pour sa fonction améliorée de séléction des fichiers et le <a href="market://details?id=com.google.zxing.client.android">lecteur de codes à barres</a> pour balayer les codes QR générés. Cliquer sur les liens ouvrira Google Play Store ou F-Droid pour l'installation.</p>
|
<p>Il vous est recommendé d'installer le <a href="market://details?id=org.openintents.filemanager">gestionnaire de fichiers OI</a> pour sa fonction améliorée de séléction des fichiers et le <a href="market://details?id=com.google.zxing.client.android">lecteur de codes à barres</a> pour balayer les codes QR générés. Cliquer sur les liens ouvrira Google Play Store ou F-Droid pour l'installation.</p>
|
||||||
|
|
||||||
<h2>J'ai trouvé un bogue dans le Porte-clefs OpenPGP !</h2>
|
<h2>J'ai trouvé un bogue dans OpenKeychain !</h2>
|
||||||
<p>Veuillez rapporter le bogue en utilisant le <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">gestionnaire de bogues du Porte-clefs OpenPGP</a>.</p>
|
<p>Veuillez rapporter le bogue en utilisant le <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">gestionnaire de bogue d'OpenKeychain</a>.</p>
|
||||||
|
|
||||||
<h2>Contribuer</h2>
|
<h2>Contribuer</h2>
|
||||||
<p>Si vous voulez nous aider à développer le Porte-clefs OpenPGP en y contribuant par du code, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">veuillez suivre notre petit guide sur Github</a>.</p>
|
<p>Si vous voulez nous aider à développer OpenKeychain en y contribuant par du code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">veuillez suivre notre petit guide sur Github</a>.</p>
|
||||||
|
|
||||||
<h2>Traductions</h2>
|
<h2>Traductions</h2>
|
||||||
<p>Aidez-nous à traduire le Porte-clefs OpenPGP ! Tout le monde peut y participer sur la <a href="https://www.transifex.com/projects/p/openpgp-keychain/">page Transifex du Porte-clefs OpenPGP Keychain</a>.</p>
|
<p>Aidez-nous à traduire le OpenKeychain ! Tout le monde peut y participer sur la <a href="https://www.transifex.com/projects/p/openpgp-keychain/">page d'OpenKeychain sur Transifex</a>.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,43 +1,45 @@
|
|||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
<body>
|
<body>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p>
|
<p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
|
||||||
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p>
|
<p><a href="http://www.openkeychain.org">OpenKeychain</a> un implementazione OpenPGP per Android.</p>
|
||||||
<p>License: GPLv3+</p>
|
<p>Licenza: GPLv3+</p>
|
||||||
|
|
||||||
<h2>Developers OpenPGP Keychain</h2>
|
<h2>Sviluppatori OpenKeychain</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Dominik Schürmann (Lead developer)</li>
|
<li>Dominik Schürmann (Capo Sviluppatore)</li>
|
||||||
<li>Ash Hughes (crypto patches)</li>
|
<li>Ash Hughes (Patch crittografia)</li>
|
||||||
<li>Brian C. Barnes</li>
|
<li>Brian C. Barnes</li>
|
||||||
<li>Bahtiar 'kalkin' Gadimov (UI)</li>
|
<li>Bahtiar 'kalkin' Gadimov (Interfaccia Utente)</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Developers APG 1.x</h2>
|
<h2>Sviluppatori APG 1.x</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>'Thialfihar' (Lead developer)</li>
|
<li>'Thialfihar' (Capo Sviluppatore)</li>
|
||||||
<li>'Senecaso' (QRCode, sign key, upload key)</li>
|
<li>'Senecaso' (QRCode, firma chiavi, caricamento chiavi)</li>
|
||||||
<li>Oliver Runge</li>
|
<li>Oliver Runge</li>
|
||||||
<li>Markus Doits</li>
|
<li>Markus Doits</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Libraries</h2>
|
<h2>Librerie</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li>
|
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Licenza Apache v2)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li>
|
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Licenza Apache v2)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li>
|
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licenza Apache v2)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li>
|
<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (Licenza MIT)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li>
|
<a href="http://code.google.com/p/zxing/">ZXing</a> (Licenza Apache v2)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
|
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licenza MIT X11)</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
|
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licenza Apache v2)</li>
|
||||||
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
|
<li>
|
||||||
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
|
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Licenza Apache v2)</li>
|
||||||
|
<li>Icone da <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Licenza Creative Commons Attribution Share-Alike 3.0)</li>
|
||||||
|
<li>Icone da <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Pubblico Dominio)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -3,106 +3,106 @@
|
|||||||
<body>
|
<body>
|
||||||
<h2>2.3</h2>
|
<h2>2.3</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li>
|
<li>rimossa esportazione non necessaria delle chiavi pubbliche quando si esportano le chiavi private (grazie a Ash Hughes)</li>
|
||||||
<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li>
|
<li>corretto impostazione data di scadenza delle chiavi (grazie a Ash Hughes)</li>
|
||||||
<li>more internal fixes when editing keys (thanks to Ash Hughes)</li>
|
<li>altre correzioni interne quando si modificano le chiavi (grazie a Ash Hughes)</li>
|
||||||
<li>querying keyservers directly from the import screen</li>
|
<li>interrogazione server delle chiavi direttamente dalla schermata di importazione</li>
|
||||||
<li>fix layout and dialog style on Android 2.2-3.0</li>
|
<li>corretto layout e dialog style su Android 2.2-3.0</li>
|
||||||
<li>fix crash on keys with empty user ids</li>
|
<li>corretto crash su chiavi con id utente vuoto</li>
|
||||||
<li>fix crash and empty lists when coming back from signing screen</li>
|
<li>corretto crash e liste vuote quando si torna dalla schermata di firma</li>
|
||||||
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li>
|
<li>Bouncy Castle (libreria crittografica) aggiornata da 1.47 a 1.50 e compilata da sorgente</li>
|
||||||
<li>fix upload of key from signing screen</li>
|
<li>corretto upload delle chiavi dalla schermata di firma</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>2.2</h2>
|
<h2>2.2</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>new design with navigation drawer</li>
|
<li>nuovo design con drawer di navigazione</li>
|
||||||
<li>new public key list design</li>
|
<li>nuovo design per la lista chiavi pubbliche</li>
|
||||||
<li>new public key view</li>
|
<li>nuova visuale chiavi pubbliche</li>
|
||||||
<li>bug fixes for importing of keys</li>
|
<li>correzione bug per importazione chiavi</li>
|
||||||
<li>key cross-certification (thanks to Ash Hughes)</li>
|
<li>Chiave certificazione incrociata (grazie a Ash Hughes)</li>
|
||||||
<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
|
<li>password UTF-8 gestite correttamente (grazie a Ash Hughes)</li>
|
||||||
<li>first version with new languages (thanks to the contributors on Transifex)</li>
|
<li>Prima versione con nuove lingue (grazie ai contributori su Transifex)</li>
|
||||||
<li>sharing of keys via QR Codes fixed and improved</li>
|
<li>condivisione di chiavi via Codici QR corretta e migliorata</li>
|
||||||
<li>package signature verification for API</li>
|
<li>Verifica firma pacchetto per API</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>2.1.1</h2>
|
<h2>2.1.1</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>API Updates, preparation for K-9 Mail integration</li>
|
<li>Aggiornamenti API, preparazione per integrazione con K-9 Mail</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>2.1</h2>
|
<h2>2.1</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>lots of bug fixes</li>
|
<li>molte correzioni di bug</li>
|
||||||
<li>new API for developers</li>
|
<li>nuove API per sviluppatori</li>
|
||||||
<li>PRNG bug fix by Google</li>
|
<li>PRNG bug fix by Google</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>2.0</h2>
|
<h2>2.0</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>complete redesign</li>
|
<li>completo restyle</li>
|
||||||
<li>share public keys via qr codes, nfc beam</li>
|
<li>condivisione chiavi pubbliche via codici qr, nfc beam</li>
|
||||||
<li>sign keys</li>
|
<li>firma chiavi</li>
|
||||||
<li>upload keys to server</li>
|
<li>Carica chiavi sul server</li>
|
||||||
<li>fixes import issues</li>
|
<li>corrette caratteristiche di importazione</li>
|
||||||
<li>new AIDL API</li>
|
<li>nuova AIDL API</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.8</h2>
|
<h2>1.0.8</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>basic keyserver support</li>
|
<li>supporto base per server delle chiavi</li>
|
||||||
<li>app2sd</li>
|
<li>app2sd</li>
|
||||||
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li>
|
<li>Aggiunte opzioni per la cache della frase di accesso: 1, 2, 4, 8 ore</li>
|
||||||
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li>
|
<li>Traduzioni: Norvegese (grazie, Sander Danielsen), Cinese (grazie, Zhang Fredrick)</li>
|
||||||
<li>bugfixes</li>
|
<li>correzione bug</li>
|
||||||
<li>optimizations</li>
|
<li>ottimizzazioni</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.7</h2>
|
<h2>1.0.7</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>fixed problem with signature verification of texts with trailing newline</li>
|
<li>corretto problema con la verifica firma di testi con capo finale</li>
|
||||||
<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li>
|
<li>maggiori opzioni per il tempo di mantenimento della cache della frase di accesso (20, 40, 60 minuti)</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.6</h2>
|
<h2>1.0.6</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>account adding crash on Froyo fixed</li>
|
<li>crash della aggiunta degli account risolto su Froyo</li>
|
||||||
<li>secure file deletion</li>
|
<li>Cancellazione sicura dei file</li>
|
||||||
<li>option to delete key file after import</li>
|
<li>opzione per cancellare file delle chiavi dopo l'importazione</li>
|
||||||
<li>stream encryption/decryption (gallery, etc.)</li>
|
<li>flusso codifica/decodifica (galleria, ecc.)</li>
|
||||||
<li>new options (language, force v3 signatures)</li>
|
<li>nuove opzioni (lingua, forza firme v3)</li>
|
||||||
<li>interface changes</li>
|
<li>cambiamenti interfaccia</li>
|
||||||
<li>bugfixes</li>
|
<li>correzione bug</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.5</h2>
|
<h2>1.0.5</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>German and Italian translation</li>
|
<li>Traduzione Italiana e Tedesca</li>
|
||||||
<li>much smaller package, due to reduced BC sources</li>
|
<li>dimensioni pacchetto ridotte, a causa della riduzione dei sorgenti BC</li>
|
||||||
<li>new preferences GUI</li>
|
<li>Nuove preferenze GUI</li>
|
||||||
<li>layout adjustment for localization</li>
|
<li>Regolazione layout per la localizzazione</li>
|
||||||
<li>signature bugfix</li>
|
<li>correzione bug firma</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.4</h2>
|
<h2>1.0.4</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>fixed another crash caused by some SDK bug with query builder</li>
|
<li>corretto altro crash causato da alcuni bug SDK con query builder</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.3</h2>
|
<h2>1.0.3</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>fixed crashes during encryption/signing and possibly key export</li>
|
<li>corretto crash durante codifica/firma e possibilita' di esportare chiave</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.2</h2>
|
<h2>1.0.2</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>filterable key lists</li>
|
<li>liste chiavi filtrabili</li>
|
||||||
<li>smarter pre-selection of encryption keys</li>
|
<li>preselezione di chiavi di codifica intelligente</li>
|
||||||
<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
|
<li>nuovo gestore intent per VIEW e SEND, permette la codifica/decodifica file all'infuori di file manager</li>
|
||||||
<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
|
<li>caratteristiche corrette e aggiunte (preselezione chiavi) per K-9 Mail. nuova build beta disponibile</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.1</h2>
|
<h2>1.0.1</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>GMail account listing was broken in 1.0.0, fixed again</li>
|
<li>elencazione account GMail corrotta in 1.0.0, corretta nuovamente</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>1.0.0</h2>
|
<h2>1.0.0</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
|
<li>integrazione K-9 Mail, APG supporto beta build di K-9 Mail</li>
|
||||||
<li>support of more file managers (including ASTRO)</li>
|
<li>supporto per altri file manager (incluso ASTRO)</li>
|
||||||
<li>Slovenian translation</li>
|
<li>traduzione Slovena</li>
|
||||||
<li>new database, much faster, less memory usage</li>
|
<li>Nuovo database, piu' veloce, utilizzo memoria ridotto</li>
|
||||||
<li>defined Intents and content provider for other apps</li>
|
<li>Definiti Intent e ContentProvider per le altre app</li>
|
||||||
<li>bugfixes</li>
|
<li>correzione bug</li>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|