diff --git a/OpenPGP-Keychain-API/example-app/build.gradle b/OpenPGP-Keychain-API/example-app/build.gradle index 99a09f094..373f83690 100644 --- a/OpenPGP-Keychain-API/example-app/build.gradle +++ b/OpenPGP-Keychain-API/example-app/build.gradle @@ -1,3 +1,4 @@ +// please leave this here, so this library builds on its own buildscript { repositories { mavenCentral() @@ -20,7 +21,7 @@ android { buildToolsVersion "19.0.1" defaultConfig { - minSdkVersion 8 + minSdkVersion 9 targetSdkVersion 19 } diff --git a/OpenPGP-Keychain-API/example-app/src/main/AndroidManifest.xml b/OpenPGP-Keychain-API/example-app/src/main/AndroidManifest.xml index 8b8c43776..39a990f72 100644 --- a/OpenPGP-Keychain-API/example-app/src/main/AndroidManifest.xml +++ b/OpenPGP-Keychain-API/example-app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionName="1.1" > --> - diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl index 4ca356fad..f9b5fc453 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl @@ -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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl index 8f9e8a0fd..ef390a7f6 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl @@ -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,12 +20,35 @@ import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.IOpenPgpCallback; import org.openintents.openpgp.IOpenPgpKeyIdsCallback; -/** - * All methods are oneway, which means they are asynchronous and non-blocking. - * Results are returned to the callback, which has to be implemented on client side. - */ interface IOpenPgpService { + /** + * Bundle params: + * api_version 1,2,3,... (current: 1) + * ascii_armor true/false (for output) + * key_ids long[] (for encrypt method) + * + * + * Bundle return: + * result_code RESULT_ERROR=0 (see error), RESULT_OK=1, RESULT_USER_INTERACTION_REQUIRED=2 (execute intent and do it again with params from intent) + * signature_result OpenPgpSignatureResult + * error OpenPgpError + * intent Intent + * + */ + + Bundle sign(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + Bundle encrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + Bundle signAndEncrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + Bundle decryptAndVerify(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + +/* + ------------------OLD-------------------------- +*/ /** * Sign * @@ -48,8 +71,9 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); - + //oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); + + /** * Encrypt * @@ -74,7 +98,7 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); + //oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Sign then encrypt @@ -100,7 +124,7 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); + //oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, @@ -126,7 +150,7 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); + //oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); /** * Get available key ids based on given user ids @@ -138,6 +162,6 @@ interface IOpenPgpService { * @param callback * Callback where to return results (different type than callback in other functions!) */ - oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback); + //oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback); } \ No newline at end of file diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl index 7a6bed1e6..7f867653d 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl @@ -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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl index e246792d0..d1d138b30 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl @@ -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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpConstants.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpConstants.java deleted file mode 100644 index b1ca1bfe6..000000000 --- a/OpenPGP-Keychain-API/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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpError.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpError.java index f108d3169..4dd2cc641 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpError.java +++ b/OpenPGP-Keychain-API/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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java index 829f8f8cf..226eeacc2 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java +++ b/OpenPGP-Keychain-API/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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java new file mode 100644 index 000000000..6efb507c4 --- /dev/null +++ b/OpenPGP-Keychain-API/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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpConstants.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpConstants.java new file mode 100644 index 000000000..3dd9391d0 --- /dev/null +++ b/OpenPGP-Keychain-API/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/OpenPgpListPreference.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java similarity index 95% rename from libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java rename to OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java index 4ddd97485..ea287a7a9 100644 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.openintents.openpgp; +package org.openintents.openpgp.util; import java.util.ArrayList; import java.util.List; @@ -70,13 +70,13 @@ public class OpenPgpListPreference extends DialogPreference { /** * 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) { + int apiVersion) { mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon, apiVersion)); } @@ -100,12 +100,12 @@ public class OpenPgpListPreference extends DialogPreference { tv.setCompoundDrawablePadding(dp10); // disable if it has the wrong api_version - if (mProviderList.get(position).apiVersion == OpenPgpConstants.REQUIRED_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.REQUIRED_API_VERSION + ")"); + + ", needs v" + OpenPgpConstants.API_VERSION + ")"); } return v; @@ -186,7 +186,7 @@ public class OpenPgpListPreference extends DialogPreference { private int apiVersion; public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, - int apiVersion) { + int apiVersion) { this.packageName = packageName; this.simpleName = simpleName; this.icon = icon; diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java similarity index 96% rename from libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java rename to OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java index f7ba06aaf..780b4606b 100644 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.openintents.openpgp; +package org.openintents.openpgp.util; import org.openintents.openpgp.IOpenPgpService; diff --git a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java similarity index 89% rename from libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java rename to OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java index 7305c47ce..6dbf76897 100644 --- a/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java +++ b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.openintents.openpgp; +package org.openintents.openpgp.util; import java.util.List; import java.util.regex.Pattern; @@ -23,7 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; -public class OpenPgpHelper { +public class OpenPgpUtils { private Context context; public static Pattern PGP_MESSAGE = Pattern.compile( @@ -34,7 +34,7 @@ public class OpenPgpHelper { ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*", Pattern.DOTALL); - public OpenPgpHelper(Context context) { + public OpenPgpUtils(Context context) { super(); this.context = context; } diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java b/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java new file mode 100644 index 000000000..20f8c36f3 --- /dev/null +++ b/OpenPGP-Keychain-API/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 diff --git a/OpenPGP-Keychain/build.gradle b/OpenPGP-Keychain/build.gradle index 66c6a0e8f..28e8c37b1 100644 --- a/OpenPGP-Keychain/build.gradle +++ b/OpenPGP-Keychain/build.gradle @@ -20,7 +20,7 @@ android { buildToolsVersion "19.0.1" defaultConfig { - minSdkVersion 8 + minSdkVersion 9 targetSdkVersion 19 } diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml index 6de35571f..45b034b97 100644 --- a/OpenPGP-Keychain/src/main/AndroidManifest.xml +++ b/OpenPGP-Keychain/src/main/AndroidManifest.xml @@ -30,7 +30,7 @@ --> diff --git a/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl index 4ca356fad..f9b5fc453 100644 --- a/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl +++ b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl @@ -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/aidl/org/openintents/openpgp/IOpenPgpService.aidl b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl index 8f9e8a0fd..ef390a7f6 100644 --- a/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl +++ b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl @@ -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,12 +20,35 @@ import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.IOpenPgpCallback; import org.openintents.openpgp.IOpenPgpKeyIdsCallback; -/** - * All methods are oneway, which means they are asynchronous and non-blocking. - * Results are returned to the callback, which has to be implemented on client side. - */ interface IOpenPgpService { + /** + * Bundle params: + * api_version 1,2,3,... (current: 1) + * ascii_armor true/false (for output) + * key_ids long[] (for encrypt method) + * + * + * Bundle return: + * result_code RESULT_ERROR=0 (see error), RESULT_OK=1, RESULT_USER_INTERACTION_REQUIRED=2 (execute intent and do it again with params from intent) + * signature_result OpenPgpSignatureResult + * error OpenPgpError + * intent Intent + * + */ + + Bundle sign(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + Bundle encrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + Bundle signAndEncrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + Bundle decryptAndVerify(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output); + + +/* + ------------------OLD-------------------------- +*/ /** * Sign * @@ -48,8 +71,9 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); - + //oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); + + /** * Encrypt * @@ -74,7 +98,7 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); + //oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Sign then encrypt @@ -100,7 +124,7 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); + //oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, @@ -126,7 +150,7 @@ interface IOpenPgpService { * @param callback * Callback where to return results */ - oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); + //oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); /** * Get available key ids based on given user ids @@ -138,6 +162,6 @@ interface IOpenPgpService { * @param callback * Callback where to return results (different type than callback in other functions!) */ - oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback); + //oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback); } \ No newline at end of file diff --git a/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl index 7a6bed1e6..7f867653d 100644 --- a/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl +++ b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpError.aidl @@ -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/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl index e246792d0..d1d138b30 100644 --- a/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl +++ b/libraries/keychain-api-library/src/main/aidl/org/openintents/openpgp/OpenPgpSignatureResult.aidl @@ -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/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/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/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java similarity index 95% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java rename to libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.java index 4ddd97485..ea287a7a9 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpListPreference.java +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpListPreference.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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.openintents.openpgp; +package org.openintents.openpgp.util; import java.util.ArrayList; import java.util.List; @@ -70,13 +70,13 @@ public class OpenPgpListPreference extends DialogPreference { /** * 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) { + int apiVersion) { mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon, apiVersion)); } @@ -100,12 +100,12 @@ public class OpenPgpListPreference extends DialogPreference { tv.setCompoundDrawablePadding(dp10); // disable if it has the wrong api_version - if (mProviderList.get(position).apiVersion == OpenPgpConstants.REQUIRED_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.REQUIRED_API_VERSION + ")"); + + ", needs v" + OpenPgpConstants.API_VERSION + ")"); } return v; @@ -186,7 +186,7 @@ public class OpenPgpListPreference extends DialogPreference { private int apiVersion; public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, - int apiVersion) { + int apiVersion) { this.packageName = packageName; this.simpleName = simpleName; this.icon = icon; diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java similarity index 96% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java rename to libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java index f7ba06aaf..780b4606b 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpServiceConnection.java +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.openintents.openpgp; +package org.openintents.openpgp.util; import org.openintents.openpgp.IOpenPgpService; diff --git a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java similarity index 89% rename from OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java rename to libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java index 7305c47ce..6dbf76897 100644 --- a/OpenPGP-Keychain-API/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/OpenPgpHelper.java +++ b/libraries/keychain-api-library/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.openintents.openpgp; +package org.openintents.openpgp.util; import java.util.List; import java.util.regex.Pattern; @@ -23,7 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; -public class OpenPgpHelper { +public class OpenPgpUtils { private Context context; public static Pattern PGP_MESSAGE = Pattern.compile( @@ -34,7 +34,7 @@ public class OpenPgpHelper { ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*", Pattern.DOTALL); - public OpenPgpHelper(Context context) { + public OpenPgpUtils(Context context) { super(); this.context = context; } 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