diff options
author | Dominik <dominik@dominikschuermann.de> | 2012-06-20 14:49:57 +0300 |
---|---|---|
committer | Dominik <dominik@dominikschuermann.de> | 2012-06-20 14:49:57 +0300 |
commit | e9c01957f4797d13518115e7e26ed015547f0891 (patch) | |
tree | c4f78c5f7f4522c7daa7ff8ddc3c8d6b705375dd /org_apg/src/org/thialfihar/android/apg/util/ApgCon.java | |
parent | 437ec9c49a61af9949dcb04dedc43d0c074f8f42 (diff) | |
download | open-keychain-e9c01957f4797d13518115e7e26ed015547f0891.tar.gz open-keychain-e9c01957f4797d13518115e7e26ed015547f0891.tar.bz2 open-keychain-e9c01957f4797d13518115e7e26ed015547f0891.zip |
working on decrypt and restructering...
Diffstat (limited to 'org_apg/src/org/thialfihar/android/apg/util/ApgCon.java')
-rw-r--r-- | org_apg/src/org/thialfihar/android/apg/util/ApgCon.java | 836 |
1 files changed, 0 insertions, 836 deletions
diff --git a/org_apg/src/org/thialfihar/android/apg/util/ApgCon.java b/org_apg/src/org/thialfihar/android/apg/util/ApgCon.java deleted file mode 100644 index 7341341d5..000000000 --- a/org_apg/src/org/thialfihar/android/apg/util/ApgCon.java +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright (C) 2011 Markus Doits <markus.doits@googlemail.com> - * - * 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.thialfihar.android.apg.util; - -import org.thialfihar.android.apg.service.IApgService2; -import org.thialfihar.android.apg.util.ApgConInterface.OnCallFinishListener; - -import android.content.ComponentName; -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 java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; - -/** - * A APG-AIDL-Wrapper - * - * <p> - * This class can be used by other projects to simplify connecting to the - * APG-AIDL-Service. Kind of wrapper of for AIDL. - * </p> - * - * <p> - * It is not used in this project. - * </p> - * - * @author Markus Doits <markus.doits@googlemail.com> - * @version 1.1rc1 - * - */ -public class ApgCon { - private static final boolean LOCAL_LOGV = true; - private static final boolean LOCAL_LOGD = true; - - private final static String TAG = "ApgCon"; - 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. - * Being unsuccessful for this number of seconds, a connection - * is assumed to be failed. - */ - public int secondsToWaitForConnection = 15; - - private class CallAsync extends AsyncTask<String, Void, Void> { - - @Override - protected Void doInBackground(String... arg) { - if( LOCAL_LOGD ) Log.d(TAG, "Async execution starting"); - call(arg[0]); - return null; - } - - protected void onPostExecute(Void res) { - if( LOCAL_LOGD ) Log.d(TAG, "Async execution finished"); - mAsyncRunning = false; - - } - - } - - private final Context mContext; - private final error mConnectionStatus; - private boolean mAsyncRunning = false; - private OnCallFinishListener mOnCallFinishListener; - - private final Bundle mResult = new Bundle(); - private final Bundle mArgs = new Bundle(); - private final ArrayList<String> mErrorList = new ArrayList<String>(); - private final ArrayList<String> mWarningList = new ArrayList<String>(); - - /** Remote service for decrypting and encrypting data */ - private IApgService2 mApgService = null; - - /** Set apgService accordingly to connection status */ - private ServiceConnection mApgConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - if( LOCAL_LOGD ) Log.d(TAG, "IApgService bound to apgService"); - mApgService = IApgService2.Stub.asInterface(service); - } - - public void onServiceDisconnected(ComponentName className) { - if( LOCAL_LOGD ) Log.d(TAG, "IApgService disconnected"); - mApgService = null; - } - }; - - /** - * Different types of local errors - */ - public static enum error { - /** - * no error - */ - NO_ERROR, - /** - * generic error - */ - GENERIC, - /** - * connection to apg service not possible - */ - CANNOT_BIND_TO_APG, - /** - * function to call not provided - */ - CALL_MISSING, - /** - * apg service does not know what to do - */ - CALL_NOT_KNOWN, - /** - * could not find APG being installed - */ - APG_NOT_FOUND, - /** - * found APG but without AIDL interface - */ - APG_AIDL_MISSING, - /** - * found APG but with wrong API - */ - APG_API_MISSMATCH - } - - private static enum ret { - ERROR, // returned from AIDL - RESULT, // returned from AIDL - WARNINGS, // mixed AIDL and LOCAL - ERRORS, // mixed AIDL and LOCAL - } - - /** - * Constructor - * - * <p> - * Creates a new ApgCon object and searches for the right APG version on - * initialization. If not found, errors are printed to the error log. - * </p> - * - * @param ctx - * the running context - */ - public ApgCon(Context ctx) { - if( LOCAL_LOGV ) Log.v(TAG, "EncryptionService created"); - mContext = ctx; - - error tmpError = null; - try { - if( LOCAL_LOGV ) Log.v(TAG, "Searching for the right APG version"); - ServiceInfo apgServices[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg", - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services; - if (apgServices == null) { - Log.e(TAG, "Could not fetch services"); - tmpError = error.GENERIC; - } else { - boolean apgServiceFound = false; - for (ServiceInfo inf : apgServices) { - if( LOCAL_LOGV ) Log.v(TAG, "Found service of APG: " + inf.name); - if (inf.name.equals("org.thialfihar.android.apg.ApgService")) { - apgServiceFound = true; - if (inf.metaData == null) { - Log.w(TAG, "Could not determine ApgService API"); - Log.w(TAG, "This probably won't work!"); - 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, "This probably won't work!"); - 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"); - tmpError = error.NO_ERROR; - } - } - } - - if (!apgServiceFound) { - Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work"); - mErrorList.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work"); - mResult.putInt(ret.ERROR.name(), error.APG_AIDL_MISSING.ordinal()); - tmpError = error.APG_NOT_FOUND; - } - } - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Could not find APG, is it installed?", e); - mErrorList.add("(LOCAL) Could not find APG, is it installed?"); - mResult.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal()); - tmpError = error.APG_NOT_FOUND; - } - - mConnectionStatus = tmpError; - - } - - /** try to connect to the apg service */ - private boolean connect() { - if( LOCAL_LOGV ) Log.v(TAG, "trying to bind the apgService to context"); - - if (mApgService != null) { - if( LOCAL_LOGV ) Log.v(TAG, "allready connected"); - return true; - } - - try { - mContext.bindService(new Intent(IApgService2.class.getName()), mApgConnection, Context.BIND_AUTO_CREATE); - } catch (Exception e) { - Log.e(TAG, "could not bind APG service", e); - return false; - } - - int waitCount = 0; - while (mApgService == null && waitCount++ < secondsToWaitForConnection) { - if( LOCAL_LOGV ) Log.v(TAG, "sleeping 1 second to wait for apg"); - android.os.SystemClock.sleep(1000); - } - - if (waitCount >= secondsToWaitForConnection) { - if( LOCAL_LOGV ) Log.v(TAG, "slept waiting for nothing!"); - return false; - } - - return true; - } - - /** - * Disconnects ApgCon from Apg - * - * <p> - * This should be called whenever all work with APG is done (e.g. everything - * you wanted to encrypt is encrypted), since connections with AIDL should - * not be upheld indefinitely. - * <p> - * - * <p> - * Also, if you destroy you end using your ApgCon-instance, this must be - * called or else the connection to APG is leaked - * </p> - */ - public void disconnect() { - if( LOCAL_LOGV ) Log.v(TAG, "disconnecting apgService"); - if (mApgService != null) { - mContext.unbindService(mApgConnection); - mApgService = null; - } - } - - private boolean initialize() { - if (mApgService == null) { - if (!connect()) { - if( LOCAL_LOGV ) Log.v(TAG, "connection to apg service failed"); - return false; - } - } - return true; - } - - /** - * Calls a function from APG's AIDL-interface - * - * <p> - * After you have set up everything with {@link #setArg(String, String)} - * (and variants), you can call a function of the AIDL-interface. This - * will: - * <ul> - * <li>start connection to the remote interface (if not already connected)</li> - * <li>call the function passed with all parameters synchronously</li> - * <li>set up everything to retrieve the result and/or warnings/errors</li> - * <li>call the callback if provided - * </ul> - * </p> - * - * <p> - * Note your thread will be blocked during execution - if you want to call - * the function asynchronously, see {@link #callAsync(String)}. - * </p> - * - * @param function - * a remote function to call - * @return true, if call successful (= no errors), else false - * - * @see #callAsync(String) - * @see #setArg(String, String) - * @see #setOnCallFinishListener(OnCallFinishListener) - */ - public boolean call(String function) { - boolean success = this.call(function, mArgs, mResult); - if (mOnCallFinishListener != null) { - try { - if( LOCAL_LOGD ) Log.d(TAG, "About to execute callback"); - mOnCallFinishListener.onCallFinish(mResult); - if( LOCAL_LOGD ) Log.d(TAG, "Callback executed"); - } catch (Exception e) { - Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e); - mWarningList.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); - } - } - return success; - } - - /** - * Calls a function of remote interface asynchronously - * - * <p> - * This does exactly the same as {@link #call(String)}, but asynchronously. - * While connection to APG and work are done in background, your thread can - * go on executing. - * <p> - * - * <p> - * To see whether the task is finished, you have two possibilities: - * <ul> - * <li>In your thread, poll {@link #isRunning()}</li> - * <li>Supply a callback with {@link #setOnCallFinishListener(OnCallFinishListener)}</li> - * </ul> - * </p> - * - * @param function - * a remote function to call - * - * @see #call(String) - * @see #isRunning() - * @see #setOnCallFinishListener(OnCallFinishListener) - */ - public void callAsync(String function) { - mAsyncRunning = true; - new CallAsync().execute(function); - } - - private boolean call(String function, Bundle pArgs, Bundle pReturn) { - - if (!initialize()) { - mErrorList.add("(LOCAL) Cannot bind to ApgService"); - mResult.putInt(ret.ERROR.name(), error.CANNOT_BIND_TO_APG.ordinal()); - return false; - } - - if (function == null || function.length() == 0) { - mErrorList.add("(LOCAL) Function to call missing"); - mResult.putInt(ret.ERROR.name(), error.CALL_MISSING.ordinal()); - return false; - } - - try { - Boolean success = (Boolean) IApgService2.class.getMethod(function, Bundle.class, Bundle.class).invoke(mApgService, pArgs, pReturn); - mErrorList.addAll(pReturn.getStringArrayList(ret.ERRORS.name())); - mWarningList.addAll(pReturn.getStringArrayList(ret.WARNINGS.name())); - return success; - } catch (NoSuchMethodException e) { - Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage(), e); - mErrorList.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage()); - mResult.putInt(ret.ERROR.name(), error.CALL_NOT_KNOWN.ordinal()); - return false; - } catch (InvocationTargetException e) { - Throwable orig = e.getTargetException(); - Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage(), orig); - mErrorList.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage()); - return false; - } catch (Exception e) { - Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage(), e); - mErrorList.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); - mResult.putInt(ret.ERROR.name(), error.GENERIC.ordinal()); - return false; - } - - } - - /** - * Set a string argument for APG - * - * <p> - * This defines a string argument for APG's AIDL-interface. - * </p> - * - * <p> - * To know what key-value-pairs are possible (or required), take a look into - * the IApgService.aidl - * </p> - * - * <p> - * Note that parameters are not reseted after a call, so you have to - * reset ({@link #clearArgs()}) them manually if you want to. - * </p> - * - * - * @param key - * the key - * @param val - * the value - * - * @see #clearArgs() - */ - public void setArg(String key, String val) { - mArgs.putString(key, val); - } - - /** - * Set a string-array argument for APG - * - * <p> - * If the AIDL-parameter is an {@literal ArrayList<String>}, you have to use - * this function. - * </p> - * - * <code> - * <pre> - * setArg("a key", new String[]{ "entry 1", "entry 2" }); - * </pre> - * </code> - * - * @param key - * the key - * @param vals - * the value - * - * @see #setArg(String, String) - */ - public void setArg(String key, String vals[]) { - ArrayList<String> list = new ArrayList<String>(); - for (String val : vals) { - list.add(val); - } - mArgs.putStringArrayList(key, list); - } - - /** - * Set up a boolean argument for APG - * - * @param key - * the key - * @param vals - * the value - * - * @see #setArg(String, String) - */ - public void setArg(String key, boolean val) { - mArgs.putBoolean(key, val); - } - - /** - * Set up a int argument for APG - * - * @param key - * the key - * @param vals - * the value - * - * @see #setArg(String, String) - */ - public void setArg(String key, int val) { - mArgs.putInt(key, val); - } - - /** - * Set up a int-array argument for APG - * <p> - * If the AIDL-parameter is an {@literal ArrayList<Integer>}, you have to - * use this function. - * </p> - * - * @param key - * the key - * @param vals - * the value - * - * @see #setArg(String, String) - */ - public void setArg(String key, int vals[]) { - ArrayList<Integer> list = new ArrayList<Integer>(); - for (int val : vals) { - list.add(val); - } - 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 - * - * <p> - * Anything the has been set up with the various - * {@link #setArg(String, String)} functions is cleared. - * </p> - * - * <p> - * Note that any warning, error, callback, result, etc. is NOT cleared with - * this. - * </p> - * - * @see #reset() - */ - public void clearArgs() { - mArgs.clear(); - } - - /** - * Return the object associated with the key - * - * @param key - * the object's key you want to return - * @return an object at position key, or null if not set - */ - public Object getArg(String key) { - return mArgs.get(key); - } - - /** - * Iterates through the errors - * - * <p> - * With this method you can iterate through all errors. The errors are only - * returned once and deleted immediately afterwards, so you can only return - * each error once. - * </p> - * - * @return a human readable description of a error that happened, or null if - * no more errors - * - * @see #hasNextError() - * @see #clearErrors() - */ - public String getNextError() { - if (mErrorList.size() != 0) - return mErrorList.remove(0); - else - return null; - } - - /** - * Check if there are any new errors - * - * @return true, if there are unreturned errors, false otherwise - * - * @see #getNextError() - */ - public boolean hasNextError() { - return mErrorList.size() != 0; - } - - /** - * Get the numeric representation of the last error - * - * <p> - * Values <100 mean the error happened locally, values >=100 mean the error - * happened at the remote side (APG). See the IApgService.aidl (or get the - * human readable description with {@link #getNextError()}) for what - * errors >=100 mean. - * </p> - * - * @return the id of the error that happened - */ - public int getError() { - if (mResult.containsKey(ret.ERROR.name())) - return mResult.getInt(ret.ERROR.name()); - else - return -1; - } - - /** - * Iterates through the warnings - * - * <p> - * With this method you can iterate through all warnings. Warnings are - * only returned once and deleted immediately afterwards, so you can only - * return each warning once. - * </p> - * - * @return a human readable description of a warning that happened, or null - * if no more warnings - * - * @see #hasNextWarning() - * @see #clearWarnings() - */ - public String getNextWarning() { - if (mWarningList.size() != 0) - return mWarningList.remove(0); - else - return null; - } - - /** - * Check if there are any new warnings - * - * @return true, if there are unreturned warnings, false otherwise - * - * @see #getNextWarning() - */ - public boolean hasNextWarning() { - return mWarningList.size() != 0; - } - - /** - * Get the result - * - * <p> - * This gets your result. After doing an encryption or decryption with APG, - * you get the output with this function. - * </p> - * - * <p> - * Note when your last remote call is unsuccessful, the result will - * still have the same value like the last successful call (or null, if no - * call was successful). To ensure you do not work with old call's results, - * either be sure to {@link #reset()} (or at least {@link #clearResult()}) - * your instance before each new call or always check that - * {@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> - * Unlike {@link #getResult()}, which only returns any en-/decrypted - * message, this function returns the complete information that was returned - * by Apg. This also includes the "RESULT", but additionally the warnings, - * errors and any other information. - * </p> - * <p> - * For warnings and errors it is suggested to use the functions that are - * provided here, namely {@link #getError()}, {@link #getNextError()}, - * {@link #get_next_Warning()} etc.), but if any call returns something non - * standard, you have access to the complete result bundle to extract the - * information. - * </p> - * - * @return the complete result bundle of the last call to apg - */ - public Bundle getResultBundle() { - return mResult; - } - - public error getConnectionStatus() { - return mConnectionStatus; - } - - /** - * Clears all unfetched errors - * - * @see #getNextError() - * @see #hasNextError() - */ - public void clearErrors() { - mErrorList.clear(); - mResult.remove(ret.ERROR.name()); - } - - /** - * Clears all unfetched warnings - * - * @see #getNextWarning() - * @see #hasNextWarning() - */ - public void clearWarnings() { - mWarningList.clear(); - } - - /** - * Clears the last mResult - * - * @see #getResult() - */ - public void clearResult() { - mResult.remove(ret.RESULT.name()); - } - - /** - * Set a callback listener when call to AIDL finishes - * - * @param obj - * a object to call back after async execution - * @see ApgConInterface - */ - public void setOnCallFinishListener(OnCallFinishListener lis) { - mOnCallFinishListener = lis; - } - - /** - * Clears any callback object - * - * @see #setOnCallFinishListener(OnCallFinishListener) - */ - public void clearOnCallFinishListener() { - mOnCallFinishListener = null; - } - - /** - * Checks if an async execution is running - * - * <p> - * If you started something with {@link #callAsync(String)}, this will - * return true if the task is still running - * </p> - * - * @return true, if an async task is still running, false otherwise - * - * @see #callAsync(String) - * - */ - public boolean isRunning() { - return mAsyncRunning; - } - - /** - * Completely resets your instance - * - * <p> - * This currently resets everything in this instance. Errors, warnings, - * results, callbacks, ... are removed. Any connection to the remote - * interface is upheld, though. - * </p> - * - * <p> - * Note when an async execution ({@link #callAsync(String)}) is - * running, it's result, warnings etc. will still be evaluated (which might - * be not what you want). Also mind that any callback you set is also - * reseted, so when finishing the execution any before defined callback will - * NOT BE TRIGGERED. - * </p> - */ - public void reset() { - clearErrors(); - clearWarnings(); - clearArgs(); - clearOnCallFinishListener(); - mResult.clear(); - } - -} |