aboutsummaryrefslogtreecommitdiffstats
path: root/src/org/thialfihar/android/apg/utils/ApgCon.java
diff options
context:
space:
mode:
authorMarkus Doits <markus.doits@googlemail.com>2011-11-04 21:22:49 +0100
committerMarkus Doits <markus.doits@googlemail.com>2011-11-04 21:22:49 +0100
commitad1657465778c05cef7a7ba9d25f97943cf68144 (patch)
tree3fadab61a099b49f8a9ac49f3d3abe5240f8996e /src/org/thialfihar/android/apg/utils/ApgCon.java
parenta7294d50b1f6a7f0ab30118602a1fcbdad0b8169 (diff)
downloadopen-keychain-ad1657465778c05cef7a7ba9d25f97943cf68144.tar.gz
open-keychain-ad1657465778c05cef7a7ba9d25f97943cf68144.tar.bz2
open-keychain-ad1657465778c05cef7a7ba9d25f97943cf68144.zip
Allow to pass large blobs and a new content provider to simplify this
Since AIDL is not for passing large data, a blob can be passed to APG by a Uri. This Uri is opened as a file by APG and read/written to. Note the file is overwritten by APG, so make sure it is a copy if you want to keep the original. With the ApgServiceBlobProvider, Apg has an own ContentProvider that can be used like mentioned above. For now the data is stored in the dir where APG stores other files and NOT DELETED after en/decryption. This is tbd. It can only be accessed by an application with the permission "org.thialfihar.android.apg.permission.STORE_BLOBS". ApgCon has been updated accordingly and can handle blobs with `setBlob` and `getBlobResult`. That is a really easy way to en/decrypt large data. Note that encrypting by blob should only be used for large files (1MB+). On all other cases, the data should be passed as as String through the AIDl-Interface, so no temporary file must be created. See ApgCon for a complete example of how to connect to the AIDL and use it. Or use it in your own project!
Diffstat (limited to 'src/org/thialfihar/android/apg/utils/ApgCon.java')
-rw-r--r--src/org/thialfihar/android/apg/utils/ApgCon.java97
1 files changed, 86 insertions, 11 deletions
diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java
index 475f7e9a9..c46ccf6b1 100644
--- a/src/org/thialfihar/android/apg/utils/ApgCon.java
+++ b/src/org/thialfihar/android/apg/utils/ApgCon.java
@@ -16,22 +16,27 @@
package org.thialfihar.android.apg.utils;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
+import org.thialfihar.android.apg.IApgService;
+import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener;
-import android.content.Context;
import android.content.ComponentName;
-import android.content.ServiceConnection;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
-import org.thialfihar.android.apg.IApgService;
-import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
/**
* A APG-AIDL-Wrapper
@@ -46,7 +51,7 @@ import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener;
* </p>
*
* @author Markus Doits <markus.doits@googlemail.com>
- * @version 1.0rc1
+ * @version 1.1rc1
*
*/
public class ApgCon {
@@ -54,7 +59,8 @@ public class ApgCon {
private static final boolean LOCAL_LOGD = true;
private final static String TAG = "ApgCon";
- private final static int API_VERSION = 1; // aidl api-version it expects
+ private final static int API_VERSION = 2; // aidl api-version it expects
+ private final static String BLOB_URI = "content://org.thialfihar.android.apg.provider.apgserviceblobprovider";
/**
* How many seconds to wait for a connection to AGP when connecting.
@@ -80,7 +86,6 @@ public class ApgCon {
}
-
private final Context mContext;
private final error mConnectionStatus;
private boolean mAsyncRunning = false;
@@ -187,9 +192,9 @@ public class ApgCon {
mWarningList.add("(LOCAL) Could not determine ApgService API");
tmpError = error.APG_API_MISSMATCH;
} else if (inf.metaData.getInt("api_version") != API_VERSION) {
- Log.w(TAG, "Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
+ Log.w(TAG, "Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
Log.w(TAG, "This probably won't work!");
- mWarningList.add("(LOCAL) Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
+ mWarningList.add("(LOCAL) Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
tmpError = error.APG_API_MISSMATCH;
} else {
if( LOCAL_LOGV ) Log.v(TAG, "Found api_version " + API_VERSION + ", everything should work");
@@ -495,6 +500,41 @@ public class ApgCon {
}
mArgs.putIntegerArrayList(key, list);
}
+
+ /**
+ * Set up binary data to en/decrypt
+ *
+ * @param is
+ * InputStream to get the data from
+ */
+ public void setBlob(InputStream is) {
+ if( LOCAL_LOGD ) Log.d(TAG, "setBlob() called");
+ // 1. get the new contentUri
+ ContentResolver cr = mContext.getContentResolver();
+ Uri contentUri = cr.insert(Uri.parse(BLOB_URI), new ContentValues());
+
+ // 2. insert binary data
+ OutputStream os = null;
+ try {
+ os = cr.openOutputStream(contentUri, "w");
+ } catch( Exception e ) {
+ Log.e(TAG, "... exception on setBlob", e);
+ }
+
+ byte[] buffer = new byte[8];
+ int len = 0;
+ try {
+ while( (len = is.read(buffer)) != -1) {
+ os.write(buffer, 0, len);
+ }
+ if(LOCAL_LOGD) Log.d(TAG, "... write finished, now closing");
+ os.close();
+ } catch (Exception e) {
+ Log.e(TAG, "... error on writing buffer", e);
+ }
+
+ mArgs.putString("BLOB", contentUri.toString() );
+ }
/**
* Clears all arguments
@@ -628,18 +668,53 @@ public class ApgCon {
* {@link #hasNextError()} is false.
* </p>
*
+ * <p>
+ * Note: When handling binary data with {@link #setBlob(InputStream)}, you
+ * get your result with {@link #getBlobResult()}.
+ * </p>
+ *
* @return the mResult of the last {@link #call(String)} or
* {@link #callAsync(String)}.
*
* @see #reset()
* @see #clearResult()
* @see #getResultBundle()
+ * @see #getBlobResult()
*/
public String getResult() {
return mResult.getString(ret.RESULT.name());
}
/**
+ * Get the binary result
+ *
+ * <p>
+ * This gets your binary result. It only works if you called {@link #setBlob(InputStream)} before.
+ *
+ * If you did not call encrypt nor decrypt, this will be the same data as you inputed.
+ * </p>
+ *
+ * @return InputStream of the binary data which was en/decrypted
+ *
+ * @see #setBlob(InputStream)
+ * @see #getResult()
+ */
+ public InputStream getBlobResult() {
+ if(mArgs.containsKey("BLOB")) {
+ ContentResolver cr = mContext.getContentResolver();
+ InputStream in = null;
+ try {
+ in = cr.openInputStream(Uri.parse(mArgs.getString("BLOB")));
+ } catch( Exception e ) {
+ Log.e(TAG, "Could not return blob in result", e);
+ }
+ return in;
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Get the result bundle
*
* <p>