mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 03:32:16 -05:00
Update openpgp-api-library for APIv7
This commit is contained in:
parent
bf344dee5d
commit
e4cfd3c886
@ -45,7 +45,7 @@ import com.fsck.k9.mailstore.LocalFolder;
|
||||
import com.fsck.k9.mailstore.StorageManager;
|
||||
import com.fsck.k9.service.MailService;
|
||||
|
||||
import org.openintents.openpgp.util.OpenPgpListPreference;
|
||||
import org.openintents.openpgp.util.OpenPgpAppPreference;
|
||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||
|
||||
|
||||
@ -174,7 +174,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private ListPreference mIdleRefreshPeriod;
|
||||
private ListPreference mMaxPushFolders;
|
||||
private boolean mHasCrypto = false;
|
||||
private OpenPgpListPreference mCryptoApp;
|
||||
private OpenPgpAppPreference mCryptoApp;
|
||||
|
||||
private PreferenceScreen mSearchScreen;
|
||||
private CheckBoxPreference mCloudSearchEnabled;
|
||||
@ -687,7 +687,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
|
||||
mHasCrypto = OpenPgpUtils.isAvailable(this);
|
||||
if (mHasCrypto) {
|
||||
mCryptoApp = (OpenPgpListPreference) findPreference(PREFERENCE_CRYPTO_APP);
|
||||
mCryptoApp = (OpenPgpAppPreference) findPreference(PREFERENCE_CRYPTO_APP);
|
||||
|
||||
mCryptoApp.setValue(String.valueOf(mAccount.getCryptoApp()));
|
||||
mCryptoApp.setSummary(mCryptoApp.getEntry());
|
||||
|
@ -285,7 +285,7 @@ public class OpenPgpHeaderView extends LinearLayout {
|
||||
}
|
||||
|
||||
private void setUserId(OpenPgpSignatureResult signatureResult) {
|
||||
final OpenPgpUtils.UserInfo userInfo = OpenPgpUtils.splitUserId(signatureResult.getPrimaryUserId());
|
||||
final OpenPgpUtils.UserId userInfo = OpenPgpUtils.splitUserId(signatureResult.getPrimaryUserId());
|
||||
if (userInfo.name != null) {
|
||||
resultSignatureName.setText(userInfo.name);
|
||||
} else {
|
||||
|
@ -466,7 +466,7 @@
|
||||
android:title="@string/account_settings_crypto"
|
||||
android:key="crypto">
|
||||
|
||||
<org.openintents.openpgp.util.OpenPgpListPreference
|
||||
<org.openintents.openpgp.util.OpenPgpAppPreference
|
||||
android:persistent="false"
|
||||
android:key="crypto_app"
|
||||
android:title="@string/account_settings_crypto_app" />
|
||||
|
@ -1,12 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.openintents.openpgp"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="9"
|
||||
android:targetSdkVersion="19" />
|
||||
package="org.openintents.openpgp">
|
||||
|
||||
<application/>
|
||||
|
||||
|
@ -57,8 +57,15 @@ public class OpenPgpApi {
|
||||
* - New extra for ACTION_DETACHED_SIGN: EXTRA_DETACHED_SIGNATURE
|
||||
* - New result for ACTION_DECRYPT_VERIFY: RESULT_DETACHED_SIGNATURE
|
||||
* - New result for ACTION_DECRYPT_VERIFY: RESULT_CHARSET
|
||||
* 7:
|
||||
* - Deprecation of ACCOUNT_NAME, please use ACTION_GET_SIGN_KEY_ID to get key id
|
||||
* - Introduce EXTRA_SIGN_KEY_ID
|
||||
* - New extra for ACTION_ENCRYPT and ACTION_SIGN_AND_ENCRYPT: EXTRA_ENABLE_COMPRESSION (default to true)
|
||||
* - Return PendingIntent to view key for signatures
|
||||
* - New result for ACTION_DECRYPT_VERIFY: RESULT_TYPE
|
||||
* - New ACTION_GET_SIGN_KEY_ID
|
||||
*/
|
||||
public static final int API_VERSION = 6;
|
||||
public static final int API_VERSION = 7;
|
||||
|
||||
/**
|
||||
* General extras
|
||||
@ -90,6 +97,9 @@ public class OpenPgpApi {
|
||||
* - end cleartext with newline
|
||||
* - remove whitespaces on line endings
|
||||
* <p/>
|
||||
* required extras:
|
||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||
* <p/>
|
||||
* optional extras:
|
||||
* String EXTRA_PASSPHRASE (key passphrase)
|
||||
*/
|
||||
@ -100,6 +110,9 @@ public class OpenPgpApi {
|
||||
* No OutputStream necessary for ACTION_DETACHED_SIGN (No magic pre-processing like in ACTION_CLEARTEXT_SIGN)!
|
||||
* The detached signature is returned separately in RESULT_DETACHED_SIGNATURE.
|
||||
* <p/>
|
||||
* required extras:
|
||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||
* <p/>
|
||||
* optional extras:
|
||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for detached signature)
|
||||
* String EXTRA_PASSPHRASE (key passphrase)
|
||||
@ -121,6 +134,7 @@ public class OpenPgpApi {
|
||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
||||
* String EXTRA_PASSPHRASE (key passphrase)
|
||||
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
||||
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default ist true)
|
||||
*/
|
||||
public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT";
|
||||
|
||||
@ -133,9 +147,11 @@ public class OpenPgpApi {
|
||||
* long[] EXTRA_KEY_IDS
|
||||
* <p/>
|
||||
* optional extras:
|
||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
||||
* String EXTRA_PASSPHRASE (key passphrase)
|
||||
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
||||
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default ist true)
|
||||
*/
|
||||
public static final String ACTION_SIGN_AND_ENCRYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT";
|
||||
|
||||
@ -146,6 +162,8 @@ public class OpenPgpApi {
|
||||
* <p/>
|
||||
* If OpenPgpSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING
|
||||
* in addition a PendingIntent is returned via RESULT_INTENT to download missing keys.
|
||||
* On all other status, in addition a PendingIntent is returned via RESULT_INTENT to open
|
||||
* the key view in OpenKeychain.
|
||||
* <p/>
|
||||
* optional extras:
|
||||
* byte[] EXTRA_DETACHED_SIGNATURE (detached signature)
|
||||
@ -154,6 +172,7 @@ public class OpenPgpApi {
|
||||
* OpenPgpSignatureResult RESULT_SIGNATURE
|
||||
* OpenPgpDecryptMetadata RESULT_METADATA
|
||||
* String RESULT_CHARSET (charset which was specified in the headers of ascii armored input, if any)
|
||||
* int RESULT_TYPE
|
||||
*/
|
||||
public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY";
|
||||
|
||||
@ -168,6 +187,17 @@ public class OpenPgpApi {
|
||||
*/
|
||||
public static final String ACTION_DECRYPT_METADATA = "org.openintents.openpgp.action.DECRYPT_METADATA";
|
||||
|
||||
/**
|
||||
* Select key id for signing
|
||||
* <p/>
|
||||
* optional extras:
|
||||
* String EXTRA_USER_ID
|
||||
* <p/>
|
||||
* returned extras:
|
||||
* long EXTRA_SIGN_KEY_ID
|
||||
*/
|
||||
public static final String ACTION_GET_SIGN_KEY_ID = "org.openintents.openpgp.action.GET_SIGN_KEY_ID";
|
||||
|
||||
/**
|
||||
* Get key ids based on given user ids (=emails)
|
||||
* <p/>
|
||||
@ -191,9 +221,11 @@ public class OpenPgpApi {
|
||||
*/
|
||||
public static final String ACTION_GET_KEY = "org.openintents.openpgp.action.GET_KEY";
|
||||
|
||||
|
||||
/* Intent extras */
|
||||
public static final String EXTRA_API_VERSION = "api_version";
|
||||
|
||||
// DEPRECATED!!!
|
||||
public static final String EXTRA_ACCOUNT_NAME = "account_name";
|
||||
|
||||
// ACTION_DETACHED_SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY
|
||||
@ -207,15 +239,20 @@ public class OpenPgpApi {
|
||||
// ENCRYPT, SIGN_AND_ENCRYPT
|
||||
public static final String EXTRA_USER_IDS = "user_ids";
|
||||
public static final String EXTRA_KEY_IDS = "key_ids";
|
||||
public static final String EXTRA_SIGN_KEY_ID = "sign_key_id";
|
||||
// optional extras:
|
||||
public static final String EXTRA_PASSPHRASE = "passphrase";
|
||||
public static final String EXTRA_ORIGINAL_FILENAME = "original_filename";
|
||||
public static final String EXTRA_ENABLE_COMPRESSION = "enable_compression";
|
||||
|
||||
// internal NFC states
|
||||
public static final String EXTRA_NFC_SIGNED_HASH = "nfc_signed_hash";
|
||||
public static final String EXTRA_NFC_SIG_CREATION_TIMESTAMP = "nfc_sig_creation_timestamp";
|
||||
public static final String EXTRA_NFC_DECRYPTED_SESSION_KEY = "nfc_decrypted_session_key";
|
||||
|
||||
// GET_SIGN_KEY_ID
|
||||
public static final String EXTRA_USER_ID = "user_id";
|
||||
|
||||
// GET_KEY
|
||||
public static final String EXTRA_KEY_ID = "key_id";
|
||||
public static final String RESULT_KEY_IDS = "key_ids";
|
||||
@ -236,12 +273,16 @@ public class OpenPgpApi {
|
||||
|
||||
// DECRYPT_VERIFY
|
||||
public static final String EXTRA_DETACHED_SIGNATURE = "detached_signature";
|
||||
|
||||
public static final String RESULT_SIGNATURE = "signature";
|
||||
public static final String RESULT_METADATA = "metadata";
|
||||
// This will be the charset which was specified in the headers of ascii armored input, if any
|
||||
public static final String RESULT_CHARSET = "charset";
|
||||
|
||||
public static final String RESULT_TYPE = "type";
|
||||
public static final int RESULT_TYPE_UNENCRYPTED_UNSIGNED = 0;
|
||||
public static final int RESULT_TYPE_ENCRYPTED = 1;
|
||||
public static final int RESULT_TYPE_SIGNED = 2;
|
||||
|
||||
IOpenPgpService mService;
|
||||
Context mContext;
|
||||
|
||||
|
@ -25,12 +25,15 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.preference.DialogPreference;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.openintents.openpgp.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -40,7 +43,7 @@ import java.util.List;
|
||||
* 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
|
||||
*/
|
||||
public class OpenPgpListPreference extends DialogPreference {
|
||||
public class OpenPgpAppPreference extends DialogPreference {
|
||||
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(
|
||||
@ -53,16 +56,17 @@ public class OpenPgpListPreference extends DialogPreference {
|
||||
PROVIDER_BLACKLIST.add("org.thialfihar.android.apg");
|
||||
}
|
||||
|
||||
private ArrayList<OpenPgpProviderEntry> mLegacyList = new ArrayList<OpenPgpProviderEntry>();
|
||||
private ArrayList<OpenPgpProviderEntry> mList = new ArrayList<OpenPgpProviderEntry>();
|
||||
private ArrayList<OpenPgpProviderEntry> mLegacyList = new ArrayList<>();
|
||||
private ArrayList<OpenPgpProviderEntry> mList = new ArrayList<>();
|
||||
|
||||
private String mSelectedPackage;
|
||||
|
||||
public OpenPgpListPreference(Context context, AttributeSet attrs) {
|
||||
public OpenPgpAppPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
populateAppList();
|
||||
}
|
||||
|
||||
public OpenPgpListPreference(Context context) {
|
||||
public OpenPgpAppPreference(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
@ -79,18 +83,177 @@ public class OpenPgpListPreference extends DialogPreference {
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialogBuilder(Builder builder) {
|
||||
|
||||
// do again, maybe an app has now been installed
|
||||
populateAppList();
|
||||
|
||||
// Init ArrayAdapter with OpenPGP Providers
|
||||
ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getContext(),
|
||||
android.R.layout.select_dialog_singlechoice, android.R.id.text1, mList) {
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
// User super class to create the View
|
||||
View v = super.getView(position, convertView, parent);
|
||||
TextView tv = (TextView) v.findViewById(android.R.id.text1);
|
||||
|
||||
// Put the image on the TextView
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(mList.get(position).icon, null,
|
||||
null, null);
|
||||
|
||||
// Add margin between image and text (support various screen densities)
|
||||
int dp10 = (int) (10 * getContext().getResources().getDisplayMetrics().density + 0.5f);
|
||||
tv.setCompoundDrawablePadding(dp10);
|
||||
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
builder.setSingleChoiceItems(adapter, getIndexOfProviderList(mSelectedPackage),
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
mSelectedPackage = entry.packageName;
|
||||
|
||||
/*
|
||||
* Clicking on an item simulates the positive button click, and dismisses
|
||||
* the dialog.
|
||||
*/
|
||||
OpenPgpAppPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* The typical interaction for list-based dialogs is to have click-on-an-item dismiss the
|
||||
* dialog instead of the user having to press 'Ok'.
|
||||
*/
|
||||
builder.setPositiveButton(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDialogClosed(boolean positiveResult) {
|
||||
super.onDialogClosed(positiveResult);
|
||||
|
||||
if (positiveResult && (mSelectedPackage != null)) {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
// Give the client a chance to ignore this change if they deem it
|
||||
// invalid
|
||||
if (!callChangeListener(mSelectedPackage)) {
|
||||
// They don't want the value to be set
|
||||
return;
|
||||
}
|
||||
|
||||
setAndPersist(mSelectedPackage);
|
||||
}
|
||||
|
||||
private void setAndPersist(String packageName) {
|
||||
mSelectedPackage = packageName;
|
||||
|
||||
// Save to persistent storage (this method will make sure this
|
||||
// preference should be persistent, along with other useful checks)
|
||||
persistString(mSelectedPackage);
|
||||
|
||||
// Data has changed, notify so UI can be refreshed!
|
||||
notifyChanged();
|
||||
|
||||
// also update summary with selected provider
|
||||
updateSummary(mSelectedPackage);
|
||||
}
|
||||
|
||||
private void updateSummary(String packageName) {
|
||||
String summary = getEntryByValue(packageName);
|
||||
setSummary(summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return getEntryByValue(mSelectedPackage);
|
||||
}
|
||||
|
||||
private int getIndexOfProviderList(String packageName) {
|
||||
for (OpenPgpProviderEntry app : mList) {
|
||||
if (app.packageName.equals(packageName)) {
|
||||
return mList.indexOf(app);
|
||||
}
|
||||
}
|
||||
|
||||
// default is "none"
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getEntry() {
|
||||
return getEntryByValue(mSelectedPackage);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return mSelectedPackage;
|
||||
}
|
||||
|
||||
public void setValue(String packageName) {
|
||||
setAndPersist(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
return a.getString(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
|
||||
if (restoreValue) {
|
||||
// Restore state
|
||||
mSelectedPackage = getPersistedString(mSelectedPackage);
|
||||
updateSummary(mSelectedPackage);
|
||||
} else {
|
||||
String value = (String) defaultValue;
|
||||
setAndPersist(value);
|
||||
updateSummary(value);
|
||||
}
|
||||
}
|
||||
|
||||
public String getEntryByValue(String packageName) {
|
||||
for (OpenPgpProviderEntry app : mList) {
|
||||
if (app.packageName.equals(packageName) && app.intent == null) {
|
||||
return app.simpleName;
|
||||
}
|
||||
}
|
||||
|
||||
return getContext().getString(R.string.openpgp_list_preference_none);
|
||||
}
|
||||
|
||||
private void populateAppList() {
|
||||
mList.clear();
|
||||
|
||||
|
||||
// add "none"-entry
|
||||
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>();
|
||||
ArrayList<OpenPgpProviderEntry> providerList = new ArrayList<>();
|
||||
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT);
|
||||
List<ResolveInfo> resInfo = getContext().getPackageManager().queryIntentServices(intent, 0);
|
||||
if (!resInfo.isEmpty()) {
|
||||
@ -128,117 +291,6 @@ public class OpenPgpListPreference extends DialogPreference {
|
||||
// add provider
|
||||
mList.addAll(providerList);
|
||||
}
|
||||
|
||||
// Init ArrayAdapter with OpenPGP Providers
|
||||
ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getContext(),
|
||||
android.R.layout.select_dialog_singlechoice, android.R.id.text1, mList) {
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
// User super class to create the View
|
||||
View v = super.getView(position, convertView, parent);
|
||||
TextView tv = (TextView) v.findViewById(android.R.id.text1);
|
||||
|
||||
// Put the image on the TextView
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(mList.get(position).icon, null,
|
||||
null, null);
|
||||
|
||||
// Add margin between image and text (support various screen densities)
|
||||
int dp10 = (int) (10 * getContext().getResources().getDisplayMetrics().density + 0.5f);
|
||||
tv.setCompoundDrawablePadding(dp10);
|
||||
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
builder.setSingleChoiceItems(adapter, getIndexOfProviderList(getValue()),
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
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
|
||||
* the dialog.
|
||||
*/
|
||||
OpenPgpListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* The typical interaction for list-based dialogs is to have click-on-an-item dismiss the
|
||||
* dialog instead of the user having to press 'Ok'.
|
||||
*/
|
||||
builder.setPositiveButton(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDialogClosed(boolean positiveResult) {
|
||||
super.onDialogClosed(positiveResult);
|
||||
|
||||
if (positiveResult && (mSelectedPackage != null)) {
|
||||
if (callChangeListener(mSelectedPackage)) {
|
||||
setValue(mSelectedPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getIndexOfProviderList(String packageName) {
|
||||
for (OpenPgpProviderEntry app : mList) {
|
||||
if (app.packageName.equals(packageName)) {
|
||||
return mList.indexOf(app);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void setValue(String packageName) {
|
||||
mSelectedPackage = packageName;
|
||||
persistString(packageName);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return mSelectedPackage;
|
||||
}
|
||||
|
||||
public String getEntry() {
|
||||
return getEntryByValue(mSelectedPackage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
return a.getString(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
|
||||
setValue(restoreValue ? getPersistedString(mSelectedPackage) : (String) defaultValue);
|
||||
}
|
||||
|
||||
public String getEntryByValue(String packageName) {
|
||||
for (OpenPgpProviderEntry app : mList) {
|
||||
if (app.packageName.equals(packageName)) {
|
||||
return app.simpleName;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class OpenPgpProviderEntry {
|
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.preference.Preference;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import org.openintents.openpgp.IOpenPgpService;
|
||||
import org.openintents.openpgp.OpenPgpError;
|
||||
import org.openintents.openpgp.R;
|
||||
|
||||
public class OpenPgpKeyPreference extends Preference {
|
||||
private long mKeyId;
|
||||
private String mOpenPgpProvider;
|
||||
private OpenPgpServiceConnection mServiceConnection;
|
||||
private String mDefaultUserId;
|
||||
|
||||
public static final int REQUEST_CODE_KEY_PREFERENCE = 9999;
|
||||
|
||||
public OpenPgpKeyPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return (mKeyId == 0) ? getContext().getString(R.string.openpgp_no_key_selected)
|
||||
: getContext().getString(R.string.openpgp_key_selected);
|
||||
}
|
||||
|
||||
private void updateEnabled() {
|
||||
if (TextUtils.isEmpty(mOpenPgpProvider)) {
|
||||
setEnabled(false);
|
||||
} else {
|
||||
setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOpenPgpProvider(String packageName) {
|
||||
mOpenPgpProvider = packageName;
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
public void setDefaultUserId(String userId) {
|
||||
mDefaultUserId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
// bind to service
|
||||
mServiceConnection = new OpenPgpServiceConnection(
|
||||
getContext().getApplicationContext(),
|
||||
mOpenPgpProvider,
|
||||
new OpenPgpServiceConnection.OnBound() {
|
||||
@Override
|
||||
public void onBound(IOpenPgpService service) {
|
||||
Log.d(OpenPgpApi.TAG, "onBound!");
|
||||
|
||||
Intent data = new Intent();
|
||||
data.setAction(OpenPgpApi.ACTION_GET_SIGN_KEY_ID);
|
||||
data.putExtra(OpenPgpApi.EXTRA_USER_ID, mDefaultUserId);
|
||||
|
||||
OpenPgpApi api = new OpenPgpApi(getContext(), mServiceConnection.getService());
|
||||
api.executeApiAsync(data, null, null, new MyCallback(REQUEST_CODE_KEY_PREFERENCE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
Log.e(OpenPgpApi.TAG, "exception when binding!", e);
|
||||
}
|
||||
}
|
||||
);
|
||||
mServiceConnection.bindToService();
|
||||
}
|
||||
|
||||
private class MyCallback implements OpenPgpApi.IOpenPgpCallback {
|
||||
int requestCode;
|
||||
|
||||
private MyCallback(int requestCode) {
|
||||
this.requestCode = requestCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReturn(Intent result) {
|
||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||
case OpenPgpApi.RESULT_CODE_SUCCESS: {
|
||||
Log.e(OpenPgpApi.TAG, "RESULT_CODE_SUCCESS: Should not happen!");
|
||||
|
||||
break;
|
||||
}
|
||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {
|
||||
|
||||
PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||
try {
|
||||
Activity act = (Activity) getContext();
|
||||
act.startIntentSenderFromChild(
|
||||
act, pi.getIntentSender(),
|
||||
requestCode, null, 0, 0, 0);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
Log.e(OpenPgpApi.TAG, "SendIntentException", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpenPgpApi.RESULT_CODE_ERROR: {
|
||||
OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
||||
Log.e(OpenPgpApi.TAG, "RESULT_CODE_ERROR: " + error.getMessage());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void save(long newValue) {
|
||||
// Give the client a chance to ignore this change if they deem it
|
||||
// invalid
|
||||
if (!callChangeListener(newValue)) {
|
||||
// They don't want the value to be set
|
||||
return;
|
||||
}
|
||||
|
||||
setAndPersist(newValue);
|
||||
}
|
||||
|
||||
private void setAndPersist(long newValue) {
|
||||
mKeyId = newValue;
|
||||
|
||||
// Save to persistent storage (this method will make sure this
|
||||
// preference should be persistent, along with other useful checks)
|
||||
persistLong(mKeyId);
|
||||
|
||||
// Data has changed, notify so UI can be refreshed!
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
// This preference type's value type is Long, so we read the default
|
||||
// value from the attributes as an Integer.
|
||||
return (long) a.getInteger(index, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
|
||||
if (restoreValue) {
|
||||
// Restore state
|
||||
mKeyId = getPersistedLong(mKeyId);
|
||||
} else {
|
||||
// Set state
|
||||
long value = (Long) defaultValue;
|
||||
setAndPersist(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
/*
|
||||
* Suppose a client uses this preference type without persisting. We
|
||||
* must save the instance state so it is able to, for example, survive
|
||||
* orientation changes.
|
||||
*/
|
||||
|
||||
final Parcelable superState = super.onSaveInstanceState();
|
||||
if (isPersistent()) {
|
||||
// No need to save instance state since it's persistent
|
||||
return superState;
|
||||
}
|
||||
|
||||
// Save the instance state
|
||||
final SavedState myState = new SavedState(superState);
|
||||
myState.keyId = mKeyId;
|
||||
myState.openPgpProvider = mOpenPgpProvider;
|
||||
myState.defaultUserId = mDefaultUserId;
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (!state.getClass().equals(SavedState.class)) {
|
||||
// Didn't save state for us in onSaveInstanceState
|
||||
super.onRestoreInstanceState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore the instance state
|
||||
SavedState myState = (SavedState) state;
|
||||
super.onRestoreInstanceState(myState.getSuperState());
|
||||
mKeyId = myState.keyId;
|
||||
mOpenPgpProvider = myState.openPgpProvider;
|
||||
mDefaultUserId = myState.defaultUserId;
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* SavedState, a subclass of {@link BaseSavedState}, will store the state
|
||||
* of MyPreference, a subclass of Preference.
|
||||
* <p/>
|
||||
* It is important to always call through to super methods.
|
||||
*/
|
||||
private static class SavedState extends BaseSavedState {
|
||||
long keyId;
|
||||
String openPgpProvider;
|
||||
String defaultUserId;
|
||||
|
||||
public SavedState(Parcel source) {
|
||||
super(source);
|
||||
|
||||
keyId = source.readInt();
|
||||
openPgpProvider = source.readString();
|
||||
defaultUserId = source.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
|
||||
dest.writeLong(keyId);
|
||||
dest.writeString(openPgpProvider);
|
||||
dest.writeString(defaultUserId);
|
||||
}
|
||||
|
||||
public SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR =
|
||||
new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public boolean handleOnActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQUEST_CODE_KEY_PREFERENCE && resultCode == Activity.RESULT_OK) {
|
||||
long keyId = data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, 0);
|
||||
save(keyId);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -71,7 +71,8 @@ public class OpenPgpUtils {
|
||||
return hexString;
|
||||
}
|
||||
|
||||
private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: (\\[.*\\]))?(?: \\((.*)\\))?(?: <(.*)>)?$");
|
||||
|
||||
private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
|
||||
|
||||
/**
|
||||
* Splits userId string into naming part, email part, and comment part
|
||||
@ -82,22 +83,42 @@ public class OpenPgpUtils {
|
||||
* @param userId
|
||||
* @return theParsedUserInfo
|
||||
*/
|
||||
public static UserInfo splitUserId(final String userId) {
|
||||
public static UserId splitUserId(final String userId) {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
final Matcher matcher = USER_ID_PATTERN.matcher(userId);
|
||||
if (matcher.matches()) {
|
||||
return new UserInfo(matcher.group(1), matcher.group(4), matcher.group(3));
|
||||
return new UserId(matcher.group(1), matcher.group(3), matcher.group(2));
|
||||
}
|
||||
}
|
||||
return new UserInfo(null, null, null);
|
||||
return new UserId(null, null, null);
|
||||
}
|
||||
|
||||
public static class UserInfo {
|
||||
/**
|
||||
* Returns a composed user id. Returns null if name is null!
|
||||
*
|
||||
* @param name
|
||||
* @param email
|
||||
* @param comment
|
||||
* @return
|
||||
*/
|
||||
public static String createUserId(UserId userId) {
|
||||
String userIdString = userId.name; // consider name a required value
|
||||
if (userIdString != null && !TextUtils.isEmpty(userId.comment)) {
|
||||
userIdString += " (" + userId.comment + ")";
|
||||
}
|
||||
if (userIdString != null && !TextUtils.isEmpty(userId.email)) {
|
||||
userIdString += " <" + userId.email + ">";
|
||||
}
|
||||
|
||||
return userIdString;
|
||||
}
|
||||
|
||||
public static class UserId {
|
||||
public final String name;
|
||||
public final String email;
|
||||
public final String comment;
|
||||
|
||||
public UserInfo(String name, String email, String comment) {
|
||||
public UserId(String name, String email, String comment) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.comment = comment;
|
||||
|
@ -3,5 +3,7 @@
|
||||
|
||||
<string name="openpgp_list_preference_none">None</string>
|
||||
<string name="openpgp_install_openkeychain_via">Install OpenKeychain via %s</string>
|
||||
<string name="openpgp_no_key_selected">No key selected</string>
|
||||
<string name="openpgp_key_selected">Key has been selected</string>
|
||||
|
||||
</resources>
|
Loading…
Reference in New Issue
Block a user