From 7939aaaa440f84a0df5524f8a1a1c04dd569eedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 14 Feb 2014 02:33:21 +0100 Subject: Introducing new ParcelFileDescriptor pipes --- .../org/openintents/openpgp/OpenPgpConstants.java | 10 - .../java/org/openintents/openpgp/OpenPgpError.java | 11 +- .../org/openintents/openpgp/OpenPgpHelper.java | 52 ------ .../openintents/openpgp/OpenPgpListPreference.java | 201 --------------------- .../openpgp/OpenPgpServiceConnection.java | 93 ---------- .../openpgp/OpenPgpSignatureResult.java | 2 +- .../org/openintents/openpgp/util/OpenPgpApi.java | 83 +++++++++ .../openintents/openpgp/util/OpenPgpConstants.java | 48 +++++ .../openpgp/util/OpenPgpListPreference.java | 201 +++++++++++++++++++++ .../openpgp/util/OpenPgpServiceConnection.java | 93 ++++++++++ .../org/openintents/openpgp/util/OpenPgpUtils.java | 52 ++++++ .../openpgp/util/ParcelFileDescriptorUtil.java | 104 +++++++++++ 12 files changed, 589 insertions(+), 361 deletions(-) delete mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpConstants.java delete mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java delete mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java delete mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java create mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java create mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpConstants.java create mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java create mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java create mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java create mode 100644 libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java (limited to 'libraries/keychain-api-library/src/main/java/org') diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpConstants.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpConstants.java deleted file mode 100644 index b1ca1bfe6..000000000 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpConstants.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.openintents.openpgp; - -public class OpenPgpConstants { - - public static final String TAG = "OpenPgp API"; - - public static final int REQUIRED_API_VERSION = 1; - public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; - -} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpError.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpError.java index f108d3169..4dd2cc641 100644 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpError.java +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpError.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2014 Dominik Schürmann * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,13 @@ import android.os.Parcel; import android.os.Parcelable; public class OpenPgpError implements Parcelable { + public static final int CLIENT_SIDE_ERROR = -1; + public static final int GENERIC_ERROR = 0; - public static final int NO_OR_WRONG_PASSPHRASE = 1; - public static final int NO_USER_IDS = 2; - public static final int USER_INTERACTION_REQUIRED = 3; + public static final int INCOMPATIBLE_API_VERSIONS = 1; + + public static final int NO_OR_WRONG_PASSPHRASE = 2; + public static final int NO_USER_IDS = 3; int errorId; String message; diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java deleted file mode 100644 index 7305c47ce..000000000 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.openpgp; - -import java.util.List; -import java.util.regex.Pattern; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.ResolveInfo; - -public class OpenPgpHelper { - private Context context; - - public static Pattern PGP_MESSAGE = Pattern.compile( - ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL); - - public static Pattern PGP_SIGNED_MESSAGE = Pattern - .compile( - ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*", - Pattern.DOTALL); - - public OpenPgpHelper(Context context) { - super(); - this.context = context; - } - - public boolean isAvailable() { - Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT); - List resInfo = context.getPackageManager().queryIntentServices(intent, 0); - if (!resInfo.isEmpty()) { - return true; - } else { - return false; - } - } - -} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java deleted file mode 100644 index 4ddd97485..000000000 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.openpgp; - -import java.util.ArrayList; -import java.util.List; - -import android.app.AlertDialog.Builder; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.graphics.drawable.Drawable; -import android.preference.DialogPreference; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ListAdapter; -import android.widget.TextView; - -public class OpenPgpListPreference extends DialogPreference { - ArrayList mProviderList = new ArrayList(); - private String mSelectedPackage; - - public OpenPgpListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - - List resInfo = context.getPackageManager().queryIntentServices( - new Intent(OpenPgpConstants.SERVICE_INTENT), PackageManager.GET_META_DATA); - if (!resInfo.isEmpty()) { - for (ResolveInfo resolveInfo : resInfo) { - if (resolveInfo.serviceInfo == null) - continue; - - String packageName = resolveInfo.serviceInfo.packageName; - String simpleName = String.valueOf(resolveInfo.serviceInfo.loadLabel(context - .getPackageManager())); - Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager()); - - // get api version - ServiceInfo si = resolveInfo.serviceInfo; - int apiVersion = si.metaData.getInt("api_version"); - - mProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon, - apiVersion)); - } - } - } - - public OpenPgpListPreference(Context context) { - this(context, null); - } - - /** - * Can be used to add "no selection" - * - * @param packageName - * @param simpleName - * @param icon - */ - public void addProvider(int position, String packageName, String simpleName, Drawable icon, - int apiVersion) { - mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon, - apiVersion)); - } - - @Override - protected void onPrepareDialogBuilder(Builder builder) { - // Init ArrayAdapter with OpenPGP Providers - ListAdapter adapter = new ArrayAdapter(getContext(), - android.R.layout.select_dialog_singlechoice, android.R.id.text1, mProviderList) { - 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(mProviderList.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); - - // disable if it has the wrong api_version - if (mProviderList.get(position).apiVersion == OpenPgpConstants.REQUIRED_API_VERSION) { - tv.setEnabled(true); - } else { - tv.setEnabled(false); - tv.setText(tv.getText() + " (API v" + mProviderList.get(position).apiVersion - + ", needs v" + OpenPgpConstants.REQUIRED_API_VERSION + ")"); - } - - return v; - } - }; - - builder.setSingleChoiceItems(adapter, getIndexOfProviderList(getValue()), - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - mSelectedPackage = mProviderList.get(which).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 : mProviderList) { - if (app.packageName.equals(packageName)) { - return mProviderList.indexOf(app); - } - } - - return -1; - } - - public void setValue(String packageName) { - mSelectedPackage = packageName; - persistString(packageName); - } - - public String getValue() { - return mSelectedPackage; - } - - public String getEntry() { - return getEntryByValue(mSelectedPackage); - } - - public String getEntryByValue(String packageName) { - for (OpenPgpProviderEntry app : mProviderList) { - if (app.packageName.equals(packageName)) { - return app.simpleName; - } - } - - return null; - } - - private static class OpenPgpProviderEntry { - private String packageName; - private String simpleName; - private Drawable icon; - private int apiVersion; - - public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, - int apiVersion) { - this.packageName = packageName; - this.simpleName = simpleName; - this.icon = icon; - this.apiVersion = apiVersion; - } - - @Override - public String toString() { - return simpleName; - } - } -} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java deleted file mode 100644 index f7ba06aaf..000000000 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.openpgp; - -import org.openintents.openpgp.IOpenPgpService; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.util.Log; - -public class OpenPgpServiceConnection { - private Context mApplicationContext; - - private IOpenPgpService mService; - private boolean mBound; - private String mCryptoProviderPackageName; - - public OpenPgpServiceConnection(Context context, String cryptoProviderPackageName) { - this.mApplicationContext = context.getApplicationContext(); - this.mCryptoProviderPackageName = cryptoProviderPackageName; - } - - public IOpenPgpService getService() { - return mService; - } - - public boolean isBound() { - return mBound; - } - - private ServiceConnection mCryptoServiceConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName name, IBinder service) { - mService = IOpenPgpService.Stub.asInterface(service); - Log.d(OpenPgpConstants.TAG, "connected to service"); - mBound = true; - } - - public void onServiceDisconnected(ComponentName name) { - mService = null; - Log.d(OpenPgpConstants.TAG, "disconnected from service"); - mBound = false; - } - }; - - /** - * If not already bound, bind! - * - * @return - */ - public boolean bindToService() { - if (mService == null && !mBound) { // if not already connected - try { - Log.d(OpenPgpConstants.TAG, "not bound yet"); - - Intent serviceIntent = new Intent(); - serviceIntent.setAction(IOpenPgpService.class.getName()); - serviceIntent.setPackage(mCryptoProviderPackageName); - mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection, - Context.BIND_AUTO_CREATE); - - return true; - } catch (Exception e) { - Log.d(OpenPgpConstants.TAG, "Exception on binding", e); - return false; - } - } else { - Log.d(OpenPgpConstants.TAG, "already bound"); - return true; - } - } - - public void unbindFromService() { - mApplicationContext.unbindService(mCryptoServiceConnection); - } - -} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java index 829f8f8cf..226eeacc2 100644 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2014 Dominik Schürmann * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java new file mode 100644 index 000000000..6efb507c4 --- /dev/null +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp.util; + +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Log; + +import org.openintents.openpgp.IOpenPgpService; +import org.openintents.openpgp.OpenPgpError; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class OpenPgpApi { + + IOpenPgpService mService; + + public OpenPgpApi(IOpenPgpService service) { + this.mService = service; + } + + public Bundle sign(InputStream is, final OutputStream os) { + try { + // send the input and output pfds + ParcelFileDescriptor input = ParcelFileDescriptorUtil.pipeFrom(is, + new ParcelFileDescriptorUtil.IThreadListener() { + + @Override + public void onThreadFinished(Thread thread) { + Log.d(OpenPgpConstants.TAG, "Copy to service finished"); + } + }); + ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os, + new ParcelFileDescriptorUtil.IThreadListener() { + + @Override + public void onThreadFinished(Thread thread) { + Log.d(OpenPgpConstants.TAG, "Service finished writing!"); + } + }); + + // blocks until result is ready + Bundle result = mService.sign(null, input, output); + // close() is required to halt the TransferThread + output.close(); + + return result; + } catch (RemoteException e) { + Log.e(OpenPgpConstants.TAG, "RemoteException", e); + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage())); + return result; + } catch (IOException e) { + Log.e(OpenPgpConstants.TAG, "IOException", e); + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage())); + return result; + } + } + + +} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpConstants.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpConstants.java new file mode 100644 index 000000000..3dd9391d0 --- /dev/null +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpConstants.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.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_KEY_IDS = "key_ids"; + + /* Bundle return */ + 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; + // execute intent and do it again with params from intent + public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2; + +} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java new file mode 100644 index 000000000..ea287a7a9 --- /dev/null +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp.util; + +import java.util.ArrayList; +import java.util.List; + +import android.app.AlertDialog.Builder; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.graphics.drawable.Drawable; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.TextView; + +public class OpenPgpListPreference extends DialogPreference { + ArrayList mProviderList = new ArrayList(); + private String mSelectedPackage; + + public OpenPgpListPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + List resInfo = context.getPackageManager().queryIntentServices( + new Intent(OpenPgpConstants.SERVICE_INTENT), PackageManager.GET_META_DATA); + if (!resInfo.isEmpty()) { + for (ResolveInfo resolveInfo : resInfo) { + if (resolveInfo.serviceInfo == null) + continue; + + String packageName = resolveInfo.serviceInfo.packageName; + String simpleName = String.valueOf(resolveInfo.serviceInfo.loadLabel(context + .getPackageManager())); + Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager()); + + // get api version + ServiceInfo si = resolveInfo.serviceInfo; + int apiVersion = si.metaData.getInt("api_version"); + + mProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon, + apiVersion)); + } + } + } + + public OpenPgpListPreference(Context context) { + this(context, null); + } + + /** + * Can be used to add "no selection" + * + * @param packageName + * @param simpleName + * @param icon + */ + public void addProvider(int position, String packageName, String simpleName, Drawable icon, + int apiVersion) { + mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon, + apiVersion)); + } + + @Override + protected void onPrepareDialogBuilder(Builder builder) { + // Init ArrayAdapter with OpenPGP Providers + ListAdapter adapter = new ArrayAdapter(getContext(), + android.R.layout.select_dialog_singlechoice, android.R.id.text1, mProviderList) { + 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(mProviderList.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); + + // disable if it has the wrong api_version + if (mProviderList.get(position).apiVersion == OpenPgpConstants.API_VERSION) { + tv.setEnabled(true); + } else { + tv.setEnabled(false); + tv.setText(tv.getText() + " (API v" + mProviderList.get(position).apiVersion + + ", needs v" + OpenPgpConstants.API_VERSION + ")"); + } + + return v; + } + }; + + builder.setSingleChoiceItems(adapter, getIndexOfProviderList(getValue()), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + mSelectedPackage = mProviderList.get(which).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 : mProviderList) { + if (app.packageName.equals(packageName)) { + return mProviderList.indexOf(app); + } + } + + return -1; + } + + public void setValue(String packageName) { + mSelectedPackage = packageName; + persistString(packageName); + } + + public String getValue() { + return mSelectedPackage; + } + + public String getEntry() { + return getEntryByValue(mSelectedPackage); + } + + public String getEntryByValue(String packageName) { + for (OpenPgpProviderEntry app : mProviderList) { + if (app.packageName.equals(packageName)) { + return app.simpleName; + } + } + + return null; + } + + private static class OpenPgpProviderEntry { + private String packageName; + private String simpleName; + private Drawable icon; + private int apiVersion; + + public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, + int apiVersion) { + this.packageName = packageName; + this.simpleName = simpleName; + this.icon = icon; + this.apiVersion = apiVersion; + } + + @Override + public String toString() { + return simpleName; + } + } +} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java new file mode 100644 index 000000000..780b4606b --- /dev/null +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp.util; + +import org.openintents.openpgp.IOpenPgpService; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.util.Log; + +public class OpenPgpServiceConnection { + private Context mApplicationContext; + + private IOpenPgpService mService; + private boolean mBound; + private String mCryptoProviderPackageName; + + public OpenPgpServiceConnection(Context context, String cryptoProviderPackageName) { + this.mApplicationContext = context.getApplicationContext(); + this.mCryptoProviderPackageName = cryptoProviderPackageName; + } + + public IOpenPgpService getService() { + return mService; + } + + public boolean isBound() { + return mBound; + } + + private ServiceConnection mCryptoServiceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IOpenPgpService.Stub.asInterface(service); + Log.d(OpenPgpConstants.TAG, "connected to service"); + mBound = true; + } + + public void onServiceDisconnected(ComponentName name) { + mService = null; + Log.d(OpenPgpConstants.TAG, "disconnected from service"); + mBound = false; + } + }; + + /** + * If not already bound, bind! + * + * @return + */ + public boolean bindToService() { + if (mService == null && !mBound) { // if not already connected + try { + Log.d(OpenPgpConstants.TAG, "not bound yet"); + + Intent serviceIntent = new Intent(); + serviceIntent.setAction(IOpenPgpService.class.getName()); + serviceIntent.setPackage(mCryptoProviderPackageName); + mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection, + Context.BIND_AUTO_CREATE); + + return true; + } catch (Exception e) { + Log.d(OpenPgpConstants.TAG, "Exception on binding", e); + return false; + } + } else { + Log.d(OpenPgpConstants.TAG, "already bound"); + return true; + } + } + + public void unbindFromService() { + mApplicationContext.unbindService(mCryptoServiceConnection); + } + +} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java new file mode 100644 index 000000000..6dbf76897 --- /dev/null +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp.util; + +import java.util.List; +import java.util.regex.Pattern; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; + +public class OpenPgpUtils { + private Context context; + + public static Pattern PGP_MESSAGE = Pattern.compile( + ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL); + + public static Pattern PGP_SIGNED_MESSAGE = Pattern + .compile( + ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*", + Pattern.DOTALL); + + public OpenPgpUtils(Context context) { + super(); + this.context = context; + } + + public boolean isAvailable() { + Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT); + List resInfo = context.getPackageManager().queryIntentServices(intent, 0); + if (!resInfo.isEmpty()) { + return true; + } else { + return false; + } + } + +} diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java new file mode 100644 index 000000000..20f8c36f3 --- /dev/null +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * 2013 Flow (http://stackoverflow.com/questions/18212152/transfer-inputstream-to-another-service-across-process-boundaries-with-parcelf) + * + * 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.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class ParcelFileDescriptorUtil { + + public interface IThreadListener { + void onThreadFinished(final Thread thread); + } + + public static ParcelFileDescriptor pipeFrom(InputStream inputStream, IThreadListener listener) + throws IOException { + ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + ParcelFileDescriptor readSide = pipe[0]; + ParcelFileDescriptor writeSide = pipe[1]; + + // start the transfer thread + new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide), + listener) + .start(); + + return readSide; + } + + public static ParcelFileDescriptor pipeTo(OutputStream outputStream, IThreadListener listener) + throws IOException { + ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + ParcelFileDescriptor readSide = pipe[0]; + ParcelFileDescriptor writeSide = pipe[1]; + + // start the transfer thread + new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(readSide), outputStream, + listener) + .start(); + + return writeSide; + } + + static class TransferThread extends Thread { + final InputStream mIn; + final OutputStream mOut; + final IThreadListener mListener; + + TransferThread(InputStream in, OutputStream out, IThreadListener listener) { + super("ParcelFileDescriptor Transfer Thread"); + mIn = in; + mOut = out; + mListener = listener; + setDaemon(true); + } + + @Override + public void run() { + byte[] buf = new byte[1024]; + int len; + + try { + while ((len = mIn.read(buf)) > 0) { + mOut.write(buf, 0, len); + } + mOut.flush(); // just to be safe + } catch (IOException e) { + Log.e(OpenPgpConstants.TAG, "TransferThread" + getId() + ": writing failed", e); + } finally { + try { + mIn.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + mOut.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (mListener != null) { + Log.d(OpenPgpConstants.TAG, "TransferThread " + getId() + " finished!"); + mListener.onThreadFinished(this); + } + } + } +} \ No newline at end of file -- cgit v1.2.3