From 14350679d1ef17fe1add86b1ec1def99f9a8f0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 1 Jul 2013 23:23:53 +0200 Subject: Restructure --- OpenPGP-Keychain/AndroidManifest.xml | 16 +- .../res/layout/crypto_consumers_activity.xml | 2 +- .../keychain/crypto_provider/CryptoService.java | 366 -------------------- .../crypto_provider/IServiceActivityCallback.aidl | 28 -- .../keychain/crypto_provider/ServiceActivity.java | 198 ----------- .../remote_api/CryptoConsumersActivity.java | 44 +++ .../remote_api/CryptoConsumersFragment.java | 85 +++++ .../keychain/remote_api/CryptoService.java | 367 +++++++++++++++++++++ .../remote_api/IServiceActivityCallback.aidl | 28 ++ .../keychain/remote_api/ServiceActivity.java | 199 +++++++++++ .../keychain/ui/CryptoConsumersActivity.java | 43 --- .../keychain/ui/CryptoConsumersFragment.java | 85 ----- .../keychain/ui/MainActivity.java | 1 + 13 files changed, 733 insertions(+), 729 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/CryptoService.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/IServiceActivityCallback.aidl delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/ServiceActivity.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersActivity.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersFragment.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/IServiceActivityCallback.aidl create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/ServiceActivity.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersActivity.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersFragment.java diff --git a/OpenPGP-Keychain/AndroidManifest.xml b/OpenPGP-Keychain/AndroidManifest.xml index d87e8ec0d..f011e6929 100644 --- a/OpenPGP-Keychain/AndroidManifest.xml +++ b/OpenPGP-Keychain/AndroidManifest.xml @@ -298,10 +298,6 @@ android:name=".ui.PreferencesActivity" android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:label="@string/title_preferences" /> - - + + - + diff --git a/OpenPGP-Keychain/res/layout/crypto_consumers_activity.xml b/OpenPGP-Keychain/res/layout/crypto_consumers_activity.xml index 87a7c1739..b314173eb 100644 --- a/OpenPGP-Keychain/res/layout/crypto_consumers_activity.xml +++ b/OpenPGP-Keychain/res/layout/crypto_consumers_activity.xml @@ -5,7 +5,7 @@ diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/CryptoService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/CryptoService.java deleted file mode 100644 index e601620ea..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/CryptoService.java +++ /dev/null @@ -1,366 +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.sufficientlysecure.keychain.crypto_provider; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.TimeUnit; - -import org.openintents.crypto.CryptoError; -import org.openintents.crypto.CryptoSignatureResult; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.helper.PgpMain; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor; - -import org.openintents.crypto.ICryptoCallback; -import org.openintents.crypto.ICryptoService; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; - -public class CryptoService extends Service { - Context mContext; - - // just one pool of 4 threads, pause on every user action needed - final ArrayBlockingQueue mPoolQueue = new ArrayBlockingQueue(20); - PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10, - TimeUnit.SECONDS, mPoolQueue); - - public static final String ACTION_SERVICE_ACTIVITY = "org.sufficientlysecure.keychain.crypto_provider.IServiceActivityCallback"; - - @Override - public void onCreate() { - super.onCreate(); - mContext = this; - Log.d(Constants.TAG, "CryptoService, onCreate()"); - } - - @Override - public void onDestroy() { - super.onDestroy(); - Log.d(Constants.TAG, "CryptoService, onDestroy()"); - } - - @Override - public IBinder onBind(Intent intent) { - // return different binder for connections from internal service activity - if (ACTION_SERVICE_ACTIVITY.equals(intent.getAction())) { - String callingPackageName = intent.getPackage(); - - // this binder can only be used from OpenPGP Keychain - if (callingPackageName.equals(Constants.PACKAGE_NAME)) { - return mBinderServiceActivity; - } else { - Log.e(Constants.TAG, "This binder can only be used from " + Constants.PACKAGE_NAME); - return null; - } - } else { - return mBinder; - } - } - - private synchronized void encryptSafe(byte[] inputBytes, String[] encryptionUserIds, - ICryptoCallback callback) throws RemoteException { - try { - // build InputData and write into OutputStream - InputStream inputStream = new ByteArrayInputStream(inputBytes); - long inputLength = inputBytes.length; - InputData inputData = new InputData(inputStream, inputLength); - - OutputStream outStream = new ByteArrayOutputStream(); - - // TODO: hardcoded... - boolean useAsciiArmor = true; - int compressionId = 2; // zlib - - // PgpMain.encryptAndSign(this, this, inputData, outStream, useAsciiArmor, - // compressionId, encryptionKeyIds, encryptionPassphrase, Preferences - // .getPreferences(this).getDefaultEncryptionAlgorithm(), - // secretKeyId, - // Preferences.getPreferences(this).getDefaultHashAlgorithm(), Preferences - // .getPreferences(this).getForceV3Signatures(), - // PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); - - outStream.close(); - } catch (Exception e) { - Log.e(Constants.TAG, "KeychainService, Exception!", e); - - try { - callback.onError(new CryptoError(0, e.getMessage())); - } catch (Exception t) { - Log.e(Constants.TAG, "Error returning exception to client", t); - } - } - } - - private synchronized void decryptAndVerifySafe(byte[] inputBytes, ICryptoCallback callback) - throws RemoteException { - try { - // build InputData and write into OutputStream - InputStream inputStream = new ByteArrayInputStream(inputBytes); - long inputLength = inputBytes.length; - InputData inputData = new InputData(inputStream, inputLength); - - OutputStream outputStream = new ByteArrayOutputStream(); - - long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream); - if (secretKeyId == Id.key.none) { - throw new PgpMain.PgpGeneralException(getString(R.string.error_noSecretKeyFound)); - } - - Log.d(Constants.TAG, "Got input:\n" + new String(inputBytes)); - - Log.d(Constants.TAG, "secretKeyId " + secretKeyId); - - String passphrase = PassphraseCacheService.getCachedPassphrase(mContext, secretKeyId); - - if (passphrase == null) { - Log.d(Constants.TAG, "No passphrase! Activity required!"); - - // start passphrase dialog - Bundle extras = new Bundle(); - extras.putLong(ServiceActivity.EXTRA_SECRET_KEY_ID, secretKeyId); - pauseQueueAndStartServiceActivity(ServiceActivity.ACTION_CACHE_PASSPHRASE, extras); - } - - // if (signedOnly) { - // resultData = PgpMain.verifyText(this, this, inputData, outStream, - // lookupUnknownKey); - // } else { - // resultData = PgpMain.decryptAndVerify(this, this, inputData, outStream, - // PassphraseCacheService.getCachedPassphrase(this, secretKeyId), - // assumeSymmetricEncryption); - // } - - Bundle outputBundle = PgpMain.decryptAndVerify(mContext, null, inputData, outputStream, - passphrase, false); - - outputStream.close(); - - byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - - // get signature informations from bundle - boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE); - long signatureKeyId = outputBundle - .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); - String signatureUserId = outputBundle - .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); - boolean signatureSuccess = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS); - boolean signatureUnknown = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN); - - CryptoSignatureResult sigResult = new CryptoSignatureResult(signatureUserId, signature, - signatureSuccess, signatureUnknown); - - // return over handler on client side - callback.onSuccess(outputBytes, sigResult); - } catch (Exception e) { - Log.e(Constants.TAG, "KeychainService, Exception!", e); - - try { - callback.onError(new CryptoError(0, e.getMessage())); - } catch (Exception t) { - Log.e(Constants.TAG, "Error returning exception to client", t); - } - } - } - - private final ICryptoService.Stub mBinder = new ICryptoService.Stub() { - - @Override - public void encrypt(final byte[] inputBytes, final String[] encryptionUserIds, - final ICryptoCallback callback) throws RemoteException { - - Runnable r = new Runnable() { - - @Override - public void run() { - try { - encryptSafe(inputBytes, encryptionUserIds, callback); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoService", e); - } - } - }; - - checkAndEnqueue(r); - } - - @Override - public void encryptAndSign(byte[] inputBytes, String[] encryptionUserIds, - String signatureUserId, ICryptoCallback callback) throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public void sign(byte[] inputBytes, String signatureUserId, ICryptoCallback callback) - throws RemoteException { - // TODO Auto-generated method stub - - } - - @Override - public void decryptAndVerify(final byte[] inputBytes, final ICryptoCallback callback) - throws RemoteException { - - Runnable r = new Runnable() { - - @Override - public void run() { - try { - decryptAndVerifySafe(inputBytes, callback); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoService", e); - } - } - }; - - checkAndEnqueue(r); - } - - @Override - public void setup(boolean asciiArmor, boolean newKeyring, String newKeyringUserId) - throws RemoteException { - // TODO Auto-generated method stub - - } - - }; - - private final IServiceActivityCallback.Stub mBinderServiceActivity = new IServiceActivityCallback.Stub() { - - @Override - public void register(boolean success, String packageName) throws RemoteException { - - if (success) { - // resume threads - if (isPackageAllowed(packageName)) { - mThreadPool.resume(); - } else { - // TODO: should not happen? - } - } else { - // TODO - mPoolQueue.clear(); - } - - } - - @Override - public void cachePassphrase(boolean success, String passphrase) throws RemoteException { - - } - - }; - - private void checkAndEnqueue(Runnable r) { - if (isCallerAllowed()) { - mThreadPool.execute(r); - - Log.d(Constants.TAG, "Enqueued runnable…"); - } else { - String[] callingPackages = getPackageManager() - .getPackagesForUid(Binder.getCallingUid()); - - Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!"); - Bundle extras = new Bundle(); - // TODO: currently simply uses first entry - extras.putString(ServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]); - pauseQueueAndStartServiceActivity(ServiceActivity.ACTION_REGISTER, extras); - - mThreadPool.execute(r); - - Log.d(Constants.TAG, "Enqueued runnable…"); - } - } - - /** - * Checks if process that binds to this service (i.e. the package name corresponding to the - * process) is in the list of allowed package names. - * - * @return true if process is allowed to use this service - */ - private boolean isCallerAllowed() { - String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); - - // is calling package allowed to use this service? - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - - if (isPackageAllowed(currentPkg)) { - return true; - } - } - - Log.d(Constants.TAG, "Caller is NOT allowed!"); - return false; - } - - private boolean isPackageAllowed(String packageName) { - Log.d(Constants.TAG, "packageName: " + packageName); - - ArrayList allowedPkgs = ProviderHelper.getCryptoConsumers(mContext); - Log.d(Constants.TAG, "allowed: " + allowedPkgs); - - // check if package is allowed to use our service - if (allowedPkgs.contains(packageName)) { - Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); - - return true; - } else if (Constants.PACKAGE_NAME.equals(packageName)) { - Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!"); - - return true; - } - - return false; - } - - private void pauseQueueAndStartServiceActivity(String action, Bundle extras) { - mThreadPool.pause(); - - Log.d(Constants.TAG, "starting activity..."); - Intent intent = new Intent(getBaseContext(), ServiceActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - // intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.setAction(action); - if (extras != null) { - intent.putExtras(extras); - } - getApplication().startActivity(intent); - } - -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/IServiceActivityCallback.aidl b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/IServiceActivityCallback.aidl deleted file mode 100644 index 61a8da06c..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/IServiceActivityCallback.aidl +++ /dev/null @@ -1,28 +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.sufficientlysecure.keychain.crypto_provider; - - -interface IServiceActivityCallback { - - - oneway void register(in boolean success, in String packageName); - - oneway void cachePassphrase(in boolean success, in String passphrase); - - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/ServiceActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/ServiceActivity.java deleted file mode 100644 index 7efce85c7..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/crypto_provider/ServiceActivity.java +++ /dev/null @@ -1,198 +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.sufficientlysecure.keychain.crypto_provider; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.PgpMain; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import com.actionbarsherlock.app.SherlockFragmentActivity; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; - -public class ServiceActivity extends SherlockFragmentActivity { - - public static final String ACTION_REGISTER = "org.sufficientlysecure.keychain.REGISTER"; - public static final String ACTION_CACHE_PASSPHRASE = "org.sufficientlysecure.keychain.CRYPTO_CACHE_PASSPHRASE"; - - public static final String EXTRA_SECRET_KEY_ID = "secretKeyId"; - public static final String EXTRA_PACKAGE_NAME = "packageName"; - - private IServiceActivityCallback mService; - private boolean mServiceBound; - - private ServiceConnection mServiceActivityConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName name, IBinder service) { - mService = IServiceActivityCallback.Stub.asInterface(service); - Log.d(Constants.TAG, "connected to ICryptoServiceActivity"); - mServiceBound = true; - } - - public void onServiceDisconnected(ComponentName name) { - mService = null; - Log.d(Constants.TAG, "disconnected from ICryptoServiceActivity"); - mServiceBound = false; - } - }; - - /** - * If not already bound, bind! - * - * @return - */ - public boolean bindToService() { - if (mService == null && !mServiceBound) { // if not already connected - try { - Log.d(Constants.TAG, "not bound yet"); - - Intent serviceIntent = new Intent(); - serviceIntent.setAction("org.openintents.crypto.ICryptoService"); - bindService(serviceIntent, mServiceActivityConnection, Context.BIND_AUTO_CREATE); - - return true; - } catch (Exception e) { - Log.d(Constants.TAG, "Exception", e); - return false; - } - } else { // already connected - Log.d(Constants.TAG, "already bound... "); - return true; - } - } - - public void unbindFromService() { - unbindService(mServiceActivityConnection); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Log.d(Constants.TAG, "onCreate…"); - - // bind to our own crypto service - bindToService(); - - handleActions(getIntent()); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - - // unbind from our crypto service - if (mServiceActivityConnection != null) { - unbindFromService(); - } - } - - protected void handleActions(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - - if (extras == null) { - extras = new Bundle(); - } - - /** - * com.android.crypto actions - */ - if (ACTION_REGISTER.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - - setContentView(R.layout.register_crypto_consumer_activity); - - Button allowButton = (Button) findViewById(R.id.register_crypto_consumer_allow); - Button disallowButton = (Button) findViewById(R.id.register_crypto_consumer_disallow); - - allowButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - ProviderHelper.addCryptoConsumer(ServiceActivity.this, packageName); - // Intent data = new Intent(); - - setResult(RESULT_OK); - finish(); - } - }); - - disallowButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - setResult(RESULT_CANCELED); - finish(); - } - }); - } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { - long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); - - showPassphraseDialog(secretKeyId); - } else { - Log.e(Constants.TAG, "Wrong action!"); - setResult(RESULT_CANCELED); - finish(); - } - } - - /** - * Shows passphrase dialog to cache a new passphrase the user enters for using it later for - * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks - * for a symmetric passphrase - */ - private void showPassphraseDialog(long secretKeyId) { - // Message is received after passphrase is cached - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - setResult(RESULT_OK); - finish(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - try { - PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(this, - messenger, secretKeyId); - - passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog"); - } catch (PgpMain.PgpGeneralException e) { - Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!"); - // send message to handler to start encryption directly - returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY); - } - } -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersActivity.java new file mode 100644 index 000000000..e3aa0ed49 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersActivity.java @@ -0,0 +1,44 @@ +package org.sufficientlysecure.keychain.remote_api; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.MainActivity; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.MenuItem; + +import android.content.Intent; +import android.os.Bundle; + +public class CryptoConsumersActivity extends SherlockFragmentActivity { + private ActionBar mActionBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mActionBar = getSupportActionBar(); + + setContentView(R.layout.crypto_consumers_activity); + + mActionBar.setDisplayShowTitleEnabled(true); + mActionBar.setDisplayHomeAsUpEnabled(true); + } + + /** + * Menu Options + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // app icon in Action Bar clicked; go home + Intent intent = new Intent(this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + default: + return super.onOptionsItemSelected(item); + } + } +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersFragment.java new file mode 100644 index 000000000..935d64560 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoConsumersFragment.java @@ -0,0 +1,85 @@ +package org.sufficientlysecure.keychain.remote_api; + +import org.sufficientlysecure.keychain.provider.KeychainContract.CryptoConsumers; +import org.sufficientlysecure.keychain.util.Log; + +import com.actionbarsherlock.app.SherlockListFragment; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.widget.SimpleCursorAdapter; + +import android.view.View; +import android.widget.ListView; + +public class CryptoConsumersFragment extends SherlockListFragment implements + LoaderManager.LoaderCallbacks { + + // This is the Adapter being used to display the list's data. + SimpleCursorAdapter mAdapter; + + // If non-null, this is the current filter the user has provided. + String mCurFilter; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // Give some text to display if there is no data. In a real + // application this would come from a resource. + setEmptyText("TODO no crypto consumers"); + + // We have a menu item to show in action bar. + setHasOptionsMenu(true); + + // Create an empty adapter we will use to display the loaded data. + mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, + null, new String[] { CryptoConsumers.PACKAGE_NAME, CryptoConsumers.PACKAGE_NAME }, + new int[] { android.R.id.text1, android.R.id.text2 }, 0); + setListAdapter(mAdapter); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + // Insert desired behavior here. + Log.i("FragmentComplexList", "Item clicked: " + id); + } + + // These are the Contacts rows that we will retrieve. + static final String[] CONSUMERS_SUMMARY_PROJECTION = new String[] { CryptoConsumers._ID, + CryptoConsumers.PACKAGE_NAME }; + + public Loader onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. + Uri baseUri = CryptoConsumers.CONTENT_URI; + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(getActivity(), baseUri, CONSUMERS_SUMMARY_PROJECTION, null, null, + CryptoConsumers.PACKAGE_NAME + " COLLATE LOCALIZED ASC"); + } + + public void onLoadFinished(Loader loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); + } + + public void onLoaderReset(Loader loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); + } + +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java new file mode 100644 index 000000000..c7d40d376 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java @@ -0,0 +1,367 @@ +/* + * 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.sufficientlysecure.keychain.remote_api; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.openintents.crypto.CryptoError; +import org.openintents.crypto.CryptoSignatureResult; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.helper.PgpMain; +import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.remote_api.IServiceActivityCallback; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor; + +import org.openintents.crypto.ICryptoCallback; +import org.openintents.crypto.ICryptoService; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; + +public class CryptoService extends Service { + Context mContext; + + // just one pool of 4 threads, pause on every user action needed + final ArrayBlockingQueue mPoolQueue = new ArrayBlockingQueue(20); + PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10, + TimeUnit.SECONDS, mPoolQueue); + + public static final String ACTION_SERVICE_ACTIVITY = "org.sufficientlysecure.keychain.crypto_provider.IServiceActivityCallback"; + + @Override + public void onCreate() { + super.onCreate(); + mContext = this; + Log.d(Constants.TAG, "CryptoService, onCreate()"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(Constants.TAG, "CryptoService, onDestroy()"); + } + + @Override + public IBinder onBind(Intent intent) { + // return different binder for connections from internal service activity + if (ACTION_SERVICE_ACTIVITY.equals(intent.getAction())) { + String callingPackageName = intent.getPackage(); + + // this binder can only be used from OpenPGP Keychain + if (callingPackageName.equals(Constants.PACKAGE_NAME)) { + return mBinderServiceActivity; + } else { + Log.e(Constants.TAG, "This binder can only be used from " + Constants.PACKAGE_NAME); + return null; + } + } else { + return mBinder; + } + } + + private synchronized void encryptSafe(byte[] inputBytes, String[] encryptionUserIds, + ICryptoCallback callback) throws RemoteException { + try { + // build InputData and write into OutputStream + InputStream inputStream = new ByteArrayInputStream(inputBytes); + long inputLength = inputBytes.length; + InputData inputData = new InputData(inputStream, inputLength); + + OutputStream outStream = new ByteArrayOutputStream(); + + // TODO: hardcoded... + boolean useAsciiArmor = true; + int compressionId = 2; // zlib + + // PgpMain.encryptAndSign(this, this, inputData, outStream, useAsciiArmor, + // compressionId, encryptionKeyIds, encryptionPassphrase, Preferences + // .getPreferences(this).getDefaultEncryptionAlgorithm(), + // secretKeyId, + // Preferences.getPreferences(this).getDefaultHashAlgorithm(), Preferences + // .getPreferences(this).getForceV3Signatures(), + // PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); + + outStream.close(); + } catch (Exception e) { + Log.e(Constants.TAG, "KeychainService, Exception!", e); + + try { + callback.onError(new CryptoError(0, e.getMessage())); + } catch (Exception t) { + Log.e(Constants.TAG, "Error returning exception to client", t); + } + } + } + + private synchronized void decryptAndVerifySafe(byte[] inputBytes, ICryptoCallback callback) + throws RemoteException { + try { + // build InputData and write into OutputStream + InputStream inputStream = new ByteArrayInputStream(inputBytes); + long inputLength = inputBytes.length; + InputData inputData = new InputData(inputStream, inputLength); + + OutputStream outputStream = new ByteArrayOutputStream(); + + long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream); + if (secretKeyId == Id.key.none) { + throw new PgpMain.PgpGeneralException(getString(R.string.error_noSecretKeyFound)); + } + + Log.d(Constants.TAG, "Got input:\n" + new String(inputBytes)); + + Log.d(Constants.TAG, "secretKeyId " + secretKeyId); + + String passphrase = PassphraseCacheService.getCachedPassphrase(mContext, secretKeyId); + + if (passphrase == null) { + Log.d(Constants.TAG, "No passphrase! Activity required!"); + + // start passphrase dialog + Bundle extras = new Bundle(); + extras.putLong(ServiceActivity.EXTRA_SECRET_KEY_ID, secretKeyId); + pauseQueueAndStartServiceActivity(ServiceActivity.ACTION_CACHE_PASSPHRASE, extras); + } + + // if (signedOnly) { + // resultData = PgpMain.verifyText(this, this, inputData, outStream, + // lookupUnknownKey); + // } else { + // resultData = PgpMain.decryptAndVerify(this, this, inputData, outStream, + // PassphraseCacheService.getCachedPassphrase(this, secretKeyId), + // assumeSymmetricEncryption); + // } + + Bundle outputBundle = PgpMain.decryptAndVerify(mContext, null, inputData, outputStream, + passphrase, false); + + outputStream.close(); + + byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + + // get signature informations from bundle + boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE); + long signatureKeyId = outputBundle + .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); + String signatureUserId = outputBundle + .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); + boolean signatureSuccess = outputBundle + .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS); + boolean signatureUnknown = outputBundle + .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN); + + CryptoSignatureResult sigResult = new CryptoSignatureResult(signatureUserId, signature, + signatureSuccess, signatureUnknown); + + // return over handler on client side + callback.onSuccess(outputBytes, sigResult); + } catch (Exception e) { + Log.e(Constants.TAG, "KeychainService, Exception!", e); + + try { + callback.onError(new CryptoError(0, e.getMessage())); + } catch (Exception t) { + Log.e(Constants.TAG, "Error returning exception to client", t); + } + } + } + + private final ICryptoService.Stub mBinder = new ICryptoService.Stub() { + + @Override + public void encrypt(final byte[] inputBytes, final String[] encryptionUserIds, + final ICryptoCallback callback) throws RemoteException { + + Runnable r = new Runnable() { + + @Override + public void run() { + try { + encryptSafe(inputBytes, encryptionUserIds, callback); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoService", e); + } + } + }; + + checkAndEnqueue(r); + } + + @Override + public void encryptAndSign(byte[] inputBytes, String[] encryptionUserIds, + String signatureUserId, ICryptoCallback callback) throws RemoteException { + // TODO Auto-generated method stub + + } + + @Override + public void sign(byte[] inputBytes, String signatureUserId, ICryptoCallback callback) + throws RemoteException { + // TODO Auto-generated method stub + + } + + @Override + public void decryptAndVerify(final byte[] inputBytes, final ICryptoCallback callback) + throws RemoteException { + + Runnable r = new Runnable() { + + @Override + public void run() { + try { + decryptAndVerifySafe(inputBytes, callback); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoService", e); + } + } + }; + + checkAndEnqueue(r); + } + + @Override + public void setup(boolean asciiArmor, boolean newKeyring, String newKeyringUserId) + throws RemoteException { + // TODO Auto-generated method stub + + } + + }; + + private final IServiceActivityCallback.Stub mBinderServiceActivity = new IServiceActivityCallback.Stub() { + + @Override + public void register(boolean success, String packageName) throws RemoteException { + + if (success) { + // resume threads + if (isPackageAllowed(packageName)) { + mThreadPool.resume(); + } else { + // TODO: should not happen? + } + } else { + // TODO + mPoolQueue.clear(); + } + + } + + @Override + public void cachePassphrase(boolean success, String passphrase) throws RemoteException { + + } + + }; + + private void checkAndEnqueue(Runnable r) { + if (isCallerAllowed()) { + mThreadPool.execute(r); + + Log.d(Constants.TAG, "Enqueued runnable…"); + } else { + String[] callingPackages = getPackageManager() + .getPackagesForUid(Binder.getCallingUid()); + + Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!"); + Bundle extras = new Bundle(); + // TODO: currently simply uses first entry + extras.putString(ServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]); + pauseQueueAndStartServiceActivity(ServiceActivity.ACTION_REGISTER, extras); + + mThreadPool.execute(r); + + Log.d(Constants.TAG, "Enqueued runnable…"); + } + } + + /** + * Checks if process that binds to this service (i.e. the package name corresponding to the + * process) is in the list of allowed package names. + * + * @return true if process is allowed to use this service + */ + private boolean isCallerAllowed() { + String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); + + // is calling package allowed to use this service? + for (int i = 0; i < callingPackages.length; i++) { + String currentPkg = callingPackages[i]; + + if (isPackageAllowed(currentPkg)) { + return true; + } + } + + Log.d(Constants.TAG, "Caller is NOT allowed!"); + return false; + } + + private boolean isPackageAllowed(String packageName) { + Log.d(Constants.TAG, "packageName: " + packageName); + + ArrayList allowedPkgs = ProviderHelper.getCryptoConsumers(mContext); + Log.d(Constants.TAG, "allowed: " + allowedPkgs); + + // check if package is allowed to use our service + if (allowedPkgs.contains(packageName)) { + Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); + + return true; + } else if (Constants.PACKAGE_NAME.equals(packageName)) { + Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!"); + + return true; + } + + return false; + } + + private void pauseQueueAndStartServiceActivity(String action, Bundle extras) { + mThreadPool.pause(); + + Log.d(Constants.TAG, "starting activity..."); + Intent intent = new Intent(getBaseContext(), ServiceActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + // intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.setAction(action); + if (extras != null) { + intent.putExtras(extras); + } + getApplication().startActivity(intent); + } + +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/IServiceActivityCallback.aidl b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/IServiceActivityCallback.aidl new file mode 100644 index 000000000..871560cc8 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/IServiceActivityCallback.aidl @@ -0,0 +1,28 @@ +/* + * 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.sufficientlysecure.keychain.remote_api; + + +interface IServiceActivityCallback { + + + oneway void register(in boolean success, in String packageName); + + oneway void cachePassphrase(in boolean success, in String passphrase); + + +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/ServiceActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/ServiceActivity.java new file mode 100644 index 000000000..055de9be1 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/ServiceActivity.java @@ -0,0 +1,199 @@ +/* + * 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.sufficientlysecure.keychain.remote_api; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.remote_api.IServiceActivityCallback; +import org.sufficientlysecure.keychain.helper.PgpMain; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; +import org.sufficientlysecure.keychain.util.Log; + +import com.actionbarsherlock.app.SherlockFragmentActivity; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; + +public class ServiceActivity extends SherlockFragmentActivity { + + public static final String ACTION_REGISTER = "org.sufficientlysecure.keychain.REGISTER"; + public static final String ACTION_CACHE_PASSPHRASE = "org.sufficientlysecure.keychain.CRYPTO_CACHE_PASSPHRASE"; + + public static final String EXTRA_SECRET_KEY_ID = "secretKeyId"; + public static final String EXTRA_PACKAGE_NAME = "packageName"; + + private IServiceActivityCallback mService; + private boolean mServiceBound; + + private ServiceConnection mServiceActivityConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IServiceActivityCallback.Stub.asInterface(service); + Log.d(Constants.TAG, "connected to ICryptoServiceActivity"); + mServiceBound = true; + } + + public void onServiceDisconnected(ComponentName name) { + mService = null; + Log.d(Constants.TAG, "disconnected from ICryptoServiceActivity"); + mServiceBound = false; + } + }; + + /** + * If not already bound, bind! + * + * @return + */ + public boolean bindToService() { + if (mService == null && !mServiceBound) { // if not already connected + try { + Log.d(Constants.TAG, "not bound yet"); + + Intent serviceIntent = new Intent(); + serviceIntent.setAction("org.openintents.crypto.ICryptoService"); + bindService(serviceIntent, mServiceActivityConnection, Context.BIND_AUTO_CREATE); + + return true; + } catch (Exception e) { + Log.d(Constants.TAG, "Exception", e); + return false; + } + } else { // already connected + Log.d(Constants.TAG, "already bound... "); + return true; + } + } + + public void unbindFromService() { + unbindService(mServiceActivityConnection); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Log.d(Constants.TAG, "onCreate…"); + + // bind to our own crypto service + bindToService(); + + handleActions(getIntent()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + // unbind from our crypto service + if (mServiceActivityConnection != null) { + unbindFromService(); + } + } + + protected void handleActions(Intent intent) { + String action = intent.getAction(); + Bundle extras = intent.getExtras(); + + if (extras == null) { + extras = new Bundle(); + } + + /** + * com.android.crypto actions + */ + if (ACTION_REGISTER.equals(action)) { + final String packageName = extras.getString(EXTRA_PACKAGE_NAME); + + setContentView(R.layout.register_crypto_consumer_activity); + + Button allowButton = (Button) findViewById(R.id.register_crypto_consumer_allow); + Button disallowButton = (Button) findViewById(R.id.register_crypto_consumer_disallow); + + allowButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + ProviderHelper.addCryptoConsumer(ServiceActivity.this, packageName); + // Intent data = new Intent(); + + setResult(RESULT_OK); + finish(); + } + }); + + disallowButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + setResult(RESULT_CANCELED); + finish(); + } + }); + } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { + long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); + + showPassphraseDialog(secretKeyId); + } else { + Log.e(Constants.TAG, "Wrong action!"); + setResult(RESULT_CANCELED); + finish(); + } + } + + /** + * Shows passphrase dialog to cache a new passphrase the user enters for using it later for + * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks + * for a symmetric passphrase + */ + private void showPassphraseDialog(long secretKeyId) { + // Message is received after passphrase is cached + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { + setResult(RESULT_OK); + finish(); + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + + try { + PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(this, + messenger, secretKeyId); + + passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog"); + } catch (PgpMain.PgpGeneralException e) { + Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!"); + // send message to handler to start encryption directly + returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY); + } + } +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersActivity.java deleted file mode 100644 index 59eaa063f..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersActivity.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.sufficientlysecure.keychain.ui; - -import org.sufficientlysecure.keychain.R; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.MenuItem; - -import android.content.Intent; -import android.os.Bundle; - -public class CryptoConsumersActivity extends SherlockFragmentActivity { - private ActionBar mActionBar; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mActionBar = getSupportActionBar(); - - setContentView(R.layout.crypto_consumers_activity); - - mActionBar.setDisplayShowTitleEnabled(true); - mActionBar.setDisplayHomeAsUpEnabled(true); - } - - /** - * Menu Options - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // app icon in Action Bar clicked; go home - Intent intent = new Intent(this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - default: - return super.onOptionsItemSelected(item); - } - } -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersFragment.java deleted file mode 100644 index 8ecc5ced1..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/CryptoConsumersFragment.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.sufficientlysecure.keychain.ui; - -import org.sufficientlysecure.keychain.provider.KeychainContract.CryptoConsumers; -import org.sufficientlysecure.keychain.util.Log; - -import com.actionbarsherlock.app.SherlockListFragment; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.widget.SimpleCursorAdapter; - -import android.view.View; -import android.widget.ListView; - -public class CryptoConsumersFragment extends SherlockListFragment implements - LoaderManager.LoaderCallbacks { - - // This is the Adapter being used to display the list's data. - SimpleCursorAdapter mAdapter; - - // If non-null, this is the current filter the user has provided. - String mCurFilter; - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText("TODO no crypto consumers"); - - // We have a menu item to show in action bar. - setHasOptionsMenu(true); - - // Create an empty adapter we will use to display the loaded data. - mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, - null, new String[] { CryptoConsumers.PACKAGE_NAME, CryptoConsumers.PACKAGE_NAME }, - new int[] { android.R.id.text1, android.R.id.text2 }, 0); - setListAdapter(mAdapter); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - // Insert desired behavior here. - Log.i("FragmentComplexList", "Item clicked: " + id); - } - - // These are the Contacts rows that we will retrieve. - static final String[] CONSUMERS_SUMMARY_PROJECTION = new String[] { CryptoConsumers._ID, - CryptoConsumers.PACKAGE_NAME }; - - public Loader onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader, so we don't care about the ID. - // First, pick the base URI to use depending on whether we are - // currently filtering. - Uri baseUri = CryptoConsumers.CONTENT_URI; - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, CONSUMERS_SUMMARY_PROJECTION, null, null, - CryptoConsumers.PACKAGE_NAME + " COLLATE LOCALIZED ASC"); - } - - public void onLoadFinished(Loader loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.swapCursor(data); - } - - public void onLoaderReset(Loader loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java index a108b3db4..434db7a29 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.remote_api.CryptoConsumersActivity; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockActivity; -- cgit v1.2.3