diff --git a/APG/res/layout/import_keys.xml b/APG/res/layout/import_keys.xml index 8e107cd96..1c2dbd0c7 100644 --- a/APG/res/layout/import_keys.xml +++ b/APG/res/layout/import_keys.xml @@ -6,7 +6,7 @@ + android:paddingLeft="12dp" + android:paddingRight="12dp" > - + android:layout_marginTop="16dp" + android:orientation="vertical" + android:paddingLeft="4dp" + android:paddingRight="4dp" > + diff --git a/APG/res/raw/help_nfc_beam.html b/APG/res/raw/help_nfc_beam.html index 31abb7ddb..80c79c4a3 100644 --- a/APG/res/raw/help_nfc_beam.html +++ b/APG/res/raw/help_nfc_beam.html @@ -8,8 +8,8 @@ And don't add newlines before or after p tags because of transifex -->
  1. Go to your partners 'Manage Public Keyrings' and long press on the keyring you want to share.
  2. Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.
  3. -
  4. After it vibrates you’ll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.
  5. -
  6. Tap the card and the content will then load on the other person’s device.
  7. +
  8. After it vibrates you’ll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.
  9. +
  10. Tap the card and the content will then load on the your device.
\ No newline at end of file diff --git a/APG/res/values/strings.xml b/APG/res/values/strings.xml index 531e1cd68..b5f55cdd3 100644 --- a/APG/res/values/strings.xml +++ b/APG/res/values/strings.xml @@ -93,7 +93,7 @@ Import from QR Code Import from NFC Export All Keyrings - Export Keyring + Export To File Delete Keyring Create Keyring Edit Keyring @@ -154,7 +154,7 @@ expired not valid %s key server(s) - fingerprint + Fingerprint: None @@ -232,6 +232,7 @@ Successfully validated and imported keyring Long press one entry in this list to show more options! This list is empty! + Successfully sent keyring with NFC Beam! done. diff --git a/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java b/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java index fed1d2156..f7bc62d4f 100644 --- a/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java +++ b/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java @@ -351,7 +351,7 @@ public class PGPHelper { return algorithmStr + ", " + keySize + "bit"; } - public static String convertToHex(byte[] fp) { + public static String convertFingerprintToHex(byte[] fp) { String fingerPrint = ""; for (int i = 0; i < fp.length; ++i) { if (i != 0 && i % 10 == 0) { @@ -382,7 +382,7 @@ public class PGPHelper { key = secretKey.getPublicKey(); } - return convertToHex(key.getFingerprint()); + return convertFingerprintToHex(key.getFingerprint()); } public static String getSmallFingerPrint(long keyId) { diff --git a/APG/src/org/thialfihar/android/apg/helper/PGPMain.java b/APG/src/org/thialfihar/android/apg/helper/PGPMain.java index cb4326f88..a8203d568 100644 --- a/APG/src/org/thialfihar/android/apg/helper/PGPMain.java +++ b/APG/src/org/thialfihar/android/apg/helper/PGPMain.java @@ -74,6 +74,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactory import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; import org.thialfihar.android.apg.provider.ProviderHelper; import org.thialfihar.android.apg.service.ApgIntentService; +import org.thialfihar.android.apg.ui.dialog.SetPassphraseDialogFragment; import org.thialfihar.android.apg.util.HkpKeyServer; import org.thialfihar.android.apg.util.InputData; import org.thialfihar.android.apg.util.PositionAwareInputStream; @@ -476,7 +477,7 @@ public class PGPMain { } public static int storeKeyRingInCache(Context context, PGPKeyRing keyring) { - int status = Integer.MIN_VALUE; // out of bounds value (Id.retrun_value.*) + int status = Integer.MIN_VALUE; // out of bounds value (Id.return_value.*) try { if (keyring instanceof PGPSecretKeyRing) { PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring; @@ -538,18 +539,20 @@ public class PGPMain { } } - public static Bundle importKeyRings(Context context, int type, InputData data, + public static Bundle importKeyRings(Context context, InputData data, ProgressDialogUpdater progress) throws ApgGeneralException, FileNotFoundException, PGPException, IOException { Bundle returnData = new Bundle(); - if (type == Id.type.secret_key) { - if (progress != null) - progress.setProgress(R.string.progress_importingSecretKeys, 0, 100); - } else { - if (progress != null) - progress.setProgress(R.string.progress_importingPublicKeys, 0, 100); - } + // if (type == Id.type.secret_key) { + // if (progress != null) + + updateProgress(progress, R.string.progress_importingSecretKeys, 0, 100); + // progress.setProgress(R.string.progress_importingSecretKeys, 0, 100); + // } else { + // if (progress != null) + // progress.setProgress(R.string.progress_importingPublicKeys, 0, 100); + // } if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { throw new ApgGeneralException(context.getString(R.string.error_externalStorageNotReady)); @@ -569,10 +572,10 @@ public class PGPMain { int status = Integer.MIN_VALUE; // out of bounds value // if this key is what we expect it to be, save it - if ((type == Id.type.secret_key && keyring instanceof PGPSecretKeyRing) - || (type == Id.type.public_key && keyring instanceof PGPPublicKeyRing)) { - status = storeKeyRingInCache(context, keyring); - } + // if ((type == Id.type.secret_key && keyring instanceof PGPSecretKeyRing) + // || (type == Id.type.public_key && keyring instanceof PGPPublicKeyRing)) { + status = storeKeyRingInCache(context, keyring); + // } if (status == Id.return_value.error) { throw new ApgGeneralException(context.getString(R.string.error_savingKeys)); @@ -589,9 +592,6 @@ public class PGPMain { updateProgress(progress, (int) (100 * progressIn.position() / data.getSize()), 100); - // TODO: needed? - // obj = objectFactory.nextObject(); - keyring = PGPConversionHelper.decodeKeyRing(bufferedInput); } } catch (EOFException e) { @@ -652,9 +652,9 @@ public class PGPMain { return returnData; } - public static Bundle getKeyRings(Context context, long[] masterKeyIds, - OutputStream outStream, ProgressDialogUpdater progress) throws ApgGeneralException, - FileNotFoundException, PGPException, IOException { + public static Bundle getKeyRings(Context context, long[] masterKeyIds, OutputStream outStream, + ProgressDialogUpdater progress) throws ApgGeneralException, FileNotFoundException, + PGPException, IOException { Bundle returnData = new Bundle(); ArmoredOutputStream out = new ArmoredOutputStream(outStream); diff --git a/APG/src/org/thialfihar/android/apg/service/ApgIntentService.java b/APG/src/org/thialfihar/android/apg/service/ApgIntentService.java index e738b4193..58afa9fa8 100644 --- a/APG/src/org/thialfihar/android/apg/service/ApgIntentService.java +++ b/APG/src/org/thialfihar/android/apg/service/ApgIntentService.java @@ -80,13 +80,13 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd public static final int ACTION_DELETE_FILE_SECURELY = 40; - public static final int ACTION_IMPORT_KEY = 50; - public static final int ACTION_EXPORT_KEY = 51; + public static final int ACTION_IMPORT_KEYRING = 50; + public static final int ACTION_EXPORT_KEYRING = 51; - public static final int ACTION_UPLOAD_KEY = 60; - public static final int ACTION_QUERY_KEY = 61; + public static final int ACTION_UPLOAD_KEYRING = 60; + public static final int ACTION_QUERY_KEYRING = 61; - public static final int ACTION_SIGN_KEY = 70; + public static final int ACTION_SIGN_KEYRING = 70; /* keys for data bundle */ @@ -137,7 +137,7 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd public static final String IMPORT_INPUT_STREAM = "importInputStream"; public static final String IMPORT_FILENAME = "importFilename"; public static final String IMPORT_BYTES = "importBytes"; - public static final String IMPORT_KEY_TYPE = "importKeyType"; + // public static final String IMPORT_KEY_TYPE = "importKeyType"; // export key public static final String EXPORT_OUTPUT_STREAM = "exportOutputStream"; @@ -629,16 +629,16 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd break; - case ACTION_IMPORT_KEY: + case ACTION_IMPORT_KEYRING: try { /* Input */ int target = data.getInt(TARGET); - int keyType = Id.type.public_key; - if (data.containsKey(IMPORT_KEY_TYPE)) { - keyType = data.getInt(IMPORT_KEY_TYPE); - } + // int keyType = Id.type.public_key; + // if (data.containsKey(IMPORT_KEY_TYPE)) { + // keyType = data.getInt(IMPORT_KEY_TYPE); + // } /* Operation */ InputStream inStream = null; @@ -670,7 +670,7 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd } Bundle resultData = new Bundle(); - resultData = PGPMain.importKeyRings(this, keyType, inputData, this); + resultData = PGPMain.importKeyRings(this, inputData, this); sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY, resultData); } catch (Exception e) { @@ -679,7 +679,7 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd break; - case ACTION_EXPORT_KEY: + case ACTION_EXPORT_KEYRING: try { /* Input */ @@ -729,7 +729,7 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd break; - case ACTION_UPLOAD_KEY: + case ACTION_UPLOAD_KEYRING: try { /* Input */ @@ -756,7 +756,7 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd break; - case ACTION_QUERY_KEY: + case ACTION_QUERY_KEYRING: try { /* Input */ @@ -787,7 +787,7 @@ public class ApgIntentService extends IntentService implements ProgressDialogUpd break; - case ACTION_SIGN_KEY: + case ACTION_SIGN_KEYRING: try { /* Input */ diff --git a/APG/src/org/thialfihar/android/apg/ui/ImportKeysActivity.java b/APG/src/org/thialfihar/android/apg/ui/ImportKeysActivity.java index be4542bbb..355214ab5 100644 --- a/APG/src/org/thialfihar/android/apg/ui/ImportKeysActivity.java +++ b/APG/src/org/thialfihar/android/apg/ui/ImportKeysActivity.java @@ -38,8 +38,9 @@ import org.thialfihar.android.apg.ui.dialog.DeleteFileDialogFragment; import org.thialfihar.android.apg.ui.dialog.FileDialogFragment; import org.thialfihar.android.apg.util.Log; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; import android.view.View; -import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragmentActivity; @@ -58,26 +59,22 @@ public class ImportKeysActivity extends SherlockFragmentActivity { // only used by IMPORT public static final String EXTRA_TEXT = "text"; - - protected String mImportFilename = Constants.path.APP_DIR + "/"; + public static final String EXTRA_KEYRING_BYTES = "keyring_bytes"; // public static final String EXTRA_KEY_ID = "keyId"; - protected String mImportData; + protected String mImportFilename; + protected byte[] mImportData; + protected boolean mDeleteAfterImport = false; FileDialogFragment mFileDialog; - private TextView mContentView; - - private String mScannedContent; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.import_keys); - mContentView = (TextView) findViewById(R.id.import_from_qr_code_content); // set actionbar without home button if called from another app OtherHelper.setActionBarBackButton(this); @@ -116,7 +113,7 @@ public class ImportKeysActivity extends SherlockFragmentActivity { return true; case Id.menu.option.import_from_file: - showImportKeysDialog(); + showImportFromFileDialog(); return true; case Id.menu.option.import_from_qr_code: @@ -156,15 +153,21 @@ public class ImportKeysActivity extends SherlockFragmentActivity { if (ACTION_IMPORT.equals(action)) { if ("file".equals(intent.getScheme()) && intent.getDataString() != null) { mImportFilename = intent.getData().getPath(); - } else { - mImportData = intent.getStringExtra(EXTRA_TEXT); + mImportData = null; + } else if (extras.containsKey(EXTRA_TEXT)) { + mImportData = intent.getStringExtra(EXTRA_TEXT).getBytes(); + mImportFilename = null; + } else if (extras.containsKey(EXTRA_KEYRING_BYTES)) { + mImportData = intent.getByteArrayExtra(EXTRA_KEYRING_BYTES); + mImportFilename = null; } - importKeys(); + loadKeyListFragment(); } else if (ACTION_IMPORT_FROM_FILE.equals(action)) { if ("file".equals(intent.getScheme()) && intent.getDataString() != null) { mImportFilename = intent.getData().getPath(); + mImportData = null; } - showImportKeysDialog(); + showImportFromFileDialog(); } else if (ACTION_IMPORT_FROM_QR_CODE.equals(action)) { importFromQrCode(); } else if (ACTION_IMPORT_FROM_NFC.equals(action)) { @@ -172,6 +175,23 @@ public class ImportKeysActivity extends SherlockFragmentActivity { } } + public void loadKeyListFragment() { + if (mImportData != null || mImportFilename != null) { + // generate list of keyrings + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + + ImportKeysListFragment listFragment = new ImportKeysListFragment(); + Bundle args = new Bundle(); + args.putByteArray(ImportKeysListFragment.ARG_KEYRING_BYTES, mImportData); + args.putString(ImportKeysListFragment.ARG_IMPORT_FILENAME, mImportFilename); + listFragment.setArguments(args); + // replace container in view with fragment + fragmentTransaction.replace(R.id.import_keys_list_container, listFragment); + fragmentTransaction.commit(); + } + } + private void importFromQrCode() { new IntentIntegrator(this).initiateScan(); } @@ -186,7 +206,7 @@ public class ImportKeysActivity extends SherlockFragmentActivity { /** * Show to dialog from where to import keys */ - public void showImportKeysDialog() { + public void showImportFromFileDialog() { // Message is received after file is selected Handler returnHandler = new Handler() { @Override @@ -196,8 +216,11 @@ public class ImportKeysActivity extends SherlockFragmentActivity { Bundle data = message.getData(); mImportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); + Log.d(Constants.TAG, "mImportFilename: " + mImportFilename); + mDeleteAfterImport = data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED); - importKeys(); + + loadKeyListFragment(); } } }; @@ -209,104 +232,14 @@ public class ImportKeysActivity extends SherlockFragmentActivity { public void run() { mFileDialog = FileDialogFragment.newInstance(messenger, getString(R.string.title_importKeys), - getString(R.string.specifyFileToImportFrom), mImportFilename, null, - Id.request.filename); + getString(R.string.specifyFileToImportFrom), Constants.path.APP_DIR + "/", + null, Id.request.filename); mFileDialog.show(getSupportFragmentManager(), "fileDialog"); } }); } - /** - * Import keys with mImportData - */ - public void importKeys() { - Log.d(Constants.TAG, "importKeys started"); - - // Send all information needed to service to import key in other thread - Intent intent = new Intent(this, ApgIntentService.class); - - intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_IMPORT_KEY); - - // fill values for this action - Bundle data = new Bundle(); - - // TODO - data.putInt(ApgIntentService.IMPORT_KEY_TYPE, Id.type.secret_key); - - if (mImportData != null) { - data.putInt(ApgIntentService.TARGET, ApgIntentService.TARGET_BYTES); - data.putByteArray(ApgIntentService.IMPORT_BYTES, mImportData.getBytes()); - } else { - data.putInt(ApgIntentService.TARGET, ApgIntentService.TARGET_FILE); - data.putString(ApgIntentService.IMPORT_FILENAME, mImportFilename); - } - - intent.putExtra(ApgIntentService.EXTRA_DATA, data); - - // Message is received after importing is done in ApgService - ApgIntentServiceHandler saveHandler = new ApgIntentServiceHandler(this, - R.string.progress_importing, ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard ApgHandler first - super.handleMessage(message); - - if (message.arg1 == ApgIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - int added = returnData.getInt(ApgIntentService.RESULT_IMPORT_ADDED); - int updated = returnData.getInt(ApgIntentService.RESULT_IMPORT_UPDATED); - int bad = returnData.getInt(ApgIntentService.RESULT_IMPORT_BAD); - String toastMessage; - if (added > 0 && updated > 0) { - toastMessage = getString(R.string.keysAddedAndUpdated, added, updated); - } else if (added > 0) { - toastMessage = getString(R.string.keysAdded, added); - } else if (updated > 0) { - toastMessage = getString(R.string.keysUpdated, updated); - } else { - toastMessage = getString(R.string.noKeysAddedOrUpdated); - } - Toast.makeText(ImportKeysActivity.this, toastMessage, Toast.LENGTH_SHORT) - .show(); - if (bad > 0) { - AlertDialog.Builder alert = new AlertDialog.Builder(ImportKeysActivity.this); - - alert.setIcon(android.R.drawable.ic_dialog_alert); - alert.setTitle(R.string.warning); - alert.setMessage(ImportKeysActivity.this.getString( - R.string.badKeysEncountered, bad)); - - alert.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - alert.setCancelable(true); - alert.create().show(); - } else if (mDeleteAfterImport) { - // everything went well, so now delete, if that was turned on - DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment - .newInstance(mImportFilename); - deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); - } - } - }; - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(ApgIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - // private void importAndSignOld(final long keyId, final String expectedFingerprint) { // if (expectedFingerprint != null && expectedFingerprint.length() > 0) { // @@ -326,7 +259,7 @@ public class ImportKeysActivity extends SherlockFragmentActivity { // PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring; // // // make sure the fingerprints match before we cache this thing - // String actualFingerprint = PGPHelper.convertToHex(publicKeyRing + // String actualFingerprint = PGPHelper.convertFingerprintToHex(publicKeyRing // .getPublicKey().getFingerprint()); // if (expectedFingerprint.equals(actualFingerprint)) { // // store the signed key in our local cache @@ -374,21 +307,36 @@ public class ImportKeysActivity extends SherlockFragmentActivity { } public void importOnClick(View view) { - Log.d(Constants.TAG, "import key started"); + Log.d(Constants.TAG, "Import key button clicked!"); + + importKeys(); + } + + /** + * Import keys with mImportData + */ + public void importKeys() { + if (mImportData != null || mImportFilename != null) { + Log.d(Constants.TAG, "importKeys started"); - if (mScannedContent != null) { // Send all information needed to service to import key in other thread Intent intent = new Intent(this, ApgIntentService.class); - intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_IMPORT_KEY); + intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_IMPORT_KEYRING); // fill values for this action Bundle data = new Bundle(); - data.putInt(ApgIntentService.IMPORT_KEY_TYPE, Id.type.public_key); + // TODO: check for key type? + // data.putInt(ApgIntentService.IMPORT_KEY_TYPE, Id.type.secret_key); - data.putInt(ApgIntentService.TARGET, ApgIntentService.TARGET_BYTES); - data.putByteArray(ApgIntentService.IMPORT_BYTES, mScannedContent.getBytes()); + if (mImportData != null) { + data.putInt(ApgIntentService.TARGET, ApgIntentService.TARGET_BYTES); + data.putByteArray(ApgIntentService.IMPORT_BYTES, mImportData); + } else { + data.putInt(ApgIntentService.TARGET, ApgIntentService.TARGET_FILE); + data.putString(ApgIntentService.IMPORT_FILENAME, mImportFilename); + } intent.putExtra(ApgIntentService.EXTRA_DATA, data); @@ -435,6 +383,11 @@ public class ImportKeysActivity extends SherlockFragmentActivity { }); alert.setCancelable(true); alert.create().show(); + } else if (mDeleteAfterImport) { + // everything went well, so now delete, if that was turned on + DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment + .newInstance(mImportFilename); + deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); } } }; @@ -449,6 +402,8 @@ public class ImportKeysActivity extends SherlockFragmentActivity { // start service with intent startService(intent); + } else { + Toast.makeText(this, R.string.error_nothingImport, Toast.LENGTH_LONG).show(); } } @@ -483,9 +438,11 @@ public class ImportKeysActivity extends SherlockFragmentActivity { data); if (scanResult != null && scanResult.getFormatName() != null) { - mScannedContent = scanResult.getContents(); + // mScannedContent = scanResult.getContents(); - mContentView.setText(mScannedContent); + mImportData = scanResult.getContents().getBytes(); + + // mContentView.setText(mScannedContent); // String[] bits = scanResult.getContents().split(","); // if (bits.length != 2) { // return; // dont know how to handle this. Not a valid code @@ -505,4 +462,12 @@ public class ImportKeysActivity extends SherlockFragmentActivity { } } } + + @Override + protected void onResume() { + super.onResume(); + + loadKeyListFragment(); + } + } diff --git a/APG/src/org/thialfihar/android/apg/ui/ImportKeysListFragment.java b/APG/src/org/thialfihar/android/apg/ui/ImportKeysListFragment.java new file mode 100644 index 000000000..157f34c28 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/ui/ImportKeysListFragment.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2012 Dominik Schürmann + * Copyright (C) 2010 Thialfihar + * + * 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.ui; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.R; +import org.thialfihar.android.apg.ui.widget.ImportKeysListLoader; +import org.thialfihar.android.apg.util.Log; + +import com.actionbarsherlock.app.SherlockListFragment; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.content.Loader; +import android.support.v4.app.LoaderManager; +import android.view.View; +import android.widget.ListView; +import android.widget.SimpleAdapter; + +public class ImportKeysListFragment extends SherlockListFragment implements + LoaderManager.LoaderCallbacks>> { + public static String ARG_KEYRING_BYTES = "bytes"; + public static String ARG_IMPORT_FILENAME = "filename"; + + byte[] mKeyringBytes; + String mImportFilename; + + private Activity mActivity; + private SimpleAdapter mAdapter; + + @Override + public void onListItemClick(ListView listView, View view, int position, long id) { + // Map item = (Map) listView.getItemAtPosition(position); + // String userId = item.get(ImportKeysListLoader.MAP_ATTR_USER_ID); + } + + /** + * Resume is called after rotating + */ + @Override + public void onResume() { + super.onResume(); + + // Start out with a progress indicator. + setListShown(false); + + // reload list + getLoaderManager().restartLoader(0, null, this); + } + + /** + * Define Adapter and Loader on create of Activity + */ + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mActivity = this.getActivity(); + + mKeyringBytes = getArguments().getByteArray(ARG_KEYRING_BYTES); + mImportFilename = getArguments().getString(ARG_IMPORT_FILENAME); + + // register long press context menu + registerForContextMenu(getListView()); + + // Give some text to display if there is no data. In a real + // application this would come from a resource. + setEmptyText(mActivity.getString(R.string.error_nothingImport)); + + // Create an empty adapter we will use to display the loaded data. + String[] from = new String[] {}; + int[] to = new int[] {}; + List> data = new ArrayList>(); + mAdapter = new SimpleAdapter(getActivity(), data, android.R.layout.two_line_list_item, + from, to); + setListAdapter(mAdapter); + + // Start out with a progress indicator. + setListShown(false); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); + } + + @Override + public Loader>> onCreateLoader(int id, Bundle args) { + return new ImportKeysListLoader(mActivity, mKeyringBytes, mImportFilename); + } + + @Override + public void onLoadFinished(Loader>> loader, + List> data) { + // Set the new data in the adapter. + // for (String item : data) { + // mAdapter.add(item); + // } + Log.d(Constants.TAG, "data: " + data); + // TODO: real swapping the data to the already defined adapter doesn't work + // Workaround: recreate adapter! + // http://stackoverflow.com/questions/2356091/android-add-function-of-arrayadapter-not-working + // mAdapter = new ArrayAdapter(mActivity, android.R.layout.two_line_list_item, + // data); + + String[] from = new String[] { ImportKeysListLoader.MAP_ATTR_USER_ID, + ImportKeysListLoader.MAP_ATTR_FINGERPINT }; + int[] to = new int[] { android.R.id.text1, android.R.id.text2 }; + mAdapter = new SimpleAdapter(getActivity(), data, android.R.layout.two_line_list_item, + from, to); + + mAdapter.notifyDataSetChanged(); + setListAdapter(mAdapter); + + // The list should now be shown. + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } + } + + @Override + public void onLoaderReset(Loader>> loader) { + // Clear the data in the adapter. + // Not available in SimpleAdapter! + // mAdapter.clear(); + } + +} diff --git a/APG/src/org/thialfihar/android/apg/ui/KeyListActivity.java b/APG/src/org/thialfihar/android/apg/ui/KeyListActivity.java index bc345fe90..ac4798f7c 100644 --- a/APG/src/org/thialfihar/android/apg/ui/KeyListActivity.java +++ b/APG/src/org/thialfihar/android/apg/ui/KeyListActivity.java @@ -260,7 +260,7 @@ public class KeyListActivity extends SherlockFragmentActivity { // Send all information needed to service to export key in other thread Intent intent = new Intent(this, ApgIntentService.class); - intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_EXPORT_KEY); + intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_EXPORT_KEYRING); // fill values for this action Bundle data = new Bundle(); diff --git a/APG/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java b/APG/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java index 593d4e5f4..c7bcb56e5 100644 --- a/APG/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java +++ b/APG/src/org/thialfihar/android/apg/ui/KeyServerQueryActivity.java @@ -169,7 +169,7 @@ public class KeyServerQueryActivity extends SherlockFragmentActivity { // Send all information needed to service to query keys in other thread Intent intent = new Intent(this, ApgIntentService.class); - intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_QUERY_KEY); + intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_QUERY_KEYRING); // fill values for this action Bundle data = new Bundle(); diff --git a/APG/src/org/thialfihar/android/apg/ui/KeyServerUploadActivity.java b/APG/src/org/thialfihar/android/apg/ui/KeyServerUploadActivity.java index db907ed48..f1ac05735 100644 --- a/APG/src/org/thialfihar/android/apg/ui/KeyServerUploadActivity.java +++ b/APG/src/org/thialfihar/android/apg/ui/KeyServerUploadActivity.java @@ -104,7 +104,7 @@ public class KeyServerUploadActivity extends SherlockFragmentActivity { // Send all information needed to service to upload key in other thread Intent intent = new Intent(this, ApgIntentService.class); - intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_UPLOAD_KEY); + intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_UPLOAD_KEYRING); // fill values for this action Bundle data = new Bundle(); diff --git a/APG/src/org/thialfihar/android/apg/ui/ShareNfcBeamActivity.java b/APG/src/org/thialfihar/android/apg/ui/ShareNfcBeamActivity.java index d1a1c198c..bdf5f6227 100644 --- a/APG/src/org/thialfihar/android/apg/ui/ShareNfcBeamActivity.java +++ b/APG/src/org/thialfihar/android/apg/ui/ShareNfcBeamActivity.java @@ -82,8 +82,6 @@ public class ShareNfcBeamActivity extends SherlockFragmentActivity implements Toast.LENGTH_LONG).show(); finish(); } else { - buildView(); - // handle actions after verifying that nfc works... handleActions(getIntent()); } @@ -99,7 +97,7 @@ public class ShareNfcBeamActivity extends SherlockFragmentActivity implements } if (ACTION_SHARE_WITH_NFC.equals(action)) { - long masterKeyId = getIntent().getExtras().getLong(EXTRA_MASTER_KEY_ID); + long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID); // get public keyring as byte array mSharedKeyringBytes = ProviderHelper.getPublicKeyRingsAsByteArray(this, @@ -121,10 +119,14 @@ public class ShareNfcBeamActivity extends SherlockFragmentActivity implements NdefMessage msg = (NdefMessage) rawMsgs[0]; // record 0 contains the MIME type, record 1 is the AAR, if present byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); - - - -// Log.d(Constants.TAG, new String()); + + Intent importIntent = new Intent(this, ImportKeysActivity.class); + importIntent.setAction(ImportKeysActivity.ACTION_IMPORT); + importIntent.putExtra(ImportKeysActivity.EXTRA_KEYRING_BYTES, receivedKeyringBytes); + + finish(); + + startActivity(importIntent); } private void buildView() { @@ -186,7 +188,8 @@ public class ShareNfcBeamActivity extends SherlockFragmentActivity implements public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_SENT: - Toast.makeText(getApplicationContext(), "Message sent!", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.nfcSuccessfull, Toast.LENGTH_LONG) + .show(); break; } } @@ -198,6 +201,10 @@ public class ShareNfcBeamActivity extends SherlockFragmentActivity implements // Check to see that the Activity started due to an Android Beam if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { handleActionNdefDiscovered(getIntent()); + } else { + // build view only when sending nfc, not when receiving, as it gets directly into Import + // activity on receiving + buildView(); } } diff --git a/APG/src/org/thialfihar/android/apg/ui/ShareQrCodeActivity.java b/APG/src/org/thialfihar/android/apg/ui/ShareQrCodeActivity.java index 38449bf58..7d4237b80 100644 --- a/APG/src/org/thialfihar/android/apg/ui/ShareQrCodeActivity.java +++ b/APG/src/org/thialfihar/android/apg/ui/ShareQrCodeActivity.java @@ -49,7 +49,7 @@ public class ShareQrCodeActivity extends SherlockFragmentActivity { } if (ACTION_SHARE_WITH_QR_CODE.equals(action)) { - long masterKeyId = getIntent().getExtras().getLong(EXTRA_MASTER_KEY_ID); + long masterKeyId = extras.getLong(EXTRA_MASTER_KEY_ID); // get public keyring as ascii armored string ArrayList keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString( diff --git a/APG/src/org/thialfihar/android/apg/ui/SignKeyActivity.java b/APG/src/org/thialfihar/android/apg/ui/SignKeyActivity.java index b970cb3d3..f8d47688c 100644 --- a/APG/src/org/thialfihar/android/apg/ui/SignKeyActivity.java +++ b/APG/src/org/thialfihar/android/apg/ui/SignKeyActivity.java @@ -198,7 +198,7 @@ public class SignKeyActivity extends SherlockFragmentActivity { // Send all information needed to service to sign key in other thread Intent intent = new Intent(this, ApgIntentService.class); - intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_SIGN_KEY); + intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_SIGN_KEYRING); // fill values for this action Bundle data = new Bundle(); @@ -249,7 +249,7 @@ public class SignKeyActivity extends SherlockFragmentActivity { // Send all information needed to service to upload key in other thread Intent intent = new Intent(this, ApgIntentService.class); - intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_UPLOAD_KEY); + intent.putExtra(ApgIntentService.EXTRA_ACTION, ApgIntentService.ACTION_UPLOAD_KEYRING); // fill values for this action Bundle data = new Bundle(); diff --git a/APG/src/org/thialfihar/android/apg/ui/widget/ImportKeysListLoader.java b/APG/src/org/thialfihar/android/apg/ui/widget/ImportKeysListLoader.java new file mode 100644 index 000000000..75a0ef06f --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/ui/widget/ImportKeysListLoader.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2012-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.thialfihar.android.apg.ui.widget; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.spongycastle.openpgp.PGPKeyRing; +import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.R; +import org.thialfihar.android.apg.helper.PGPConversionHelper; +import org.thialfihar.android.apg.helper.PGPHelper; +import org.thialfihar.android.apg.util.InputData; +import org.thialfihar.android.apg.util.Log; +import org.thialfihar.android.apg.util.PositionAwareInputStream; + +import android.content.Context; +import android.support.v4.content.AsyncTaskLoader; + +/** + * A custom Loader to search for bad adware apps, based on + * https://github.com/brosmike/AirPush-Detector. Daniel Bjorge licensed it under Apachev2 after + * asking him by mail. + */ +public class ImportKeysListLoader extends AsyncTaskLoader>> { + public static final String MAP_ATTR_USER_ID = "user_id"; + public static final String MAP_ATTR_FINGERPINT = "fingerprint"; + + Context mContext; + List mItems; + + byte[] mKeyringBytes; + String mImportFilename; + + public ImportKeysListLoader(Context context, byte[] keyringBytes, String importFilename) { + super(context); + this.mContext = context; + this.mKeyringBytes = keyringBytes; + this.mImportFilename = importFilename; + } + + @Override + public List> loadInBackground() { + InputData inputData = null; + if (mKeyringBytes != null) { + inputData = new InputData(new ByteArrayInputStream(mKeyringBytes), mKeyringBytes.length); + } else { + try { + inputData = new InputData(new FileInputStream(mImportFilename), + mImportFilename.length()); + } catch (FileNotFoundException e) { + Log.e(Constants.TAG, "Failed to init FileInputStream!", e); + } + } + + return generateListOfKeyrings(inputData); + } + + @Override + protected void onReset() { + super.onReset(); + + // Ensure the loader is stopped + onStopLoading(); + } + + @Override + protected void onStartLoading() { + forceLoad(); + } + + @Override + protected void onStopLoading() { + cancelLoad(); + } + + @Override + public void deliverResult(List> data) { + super.deliverResult(data); + } + + /** + * Similar to PGPMain.importKeyRings + * + * @param keyringBytes + * @return + */ + private ArrayList> generateListOfKeyrings(InputData inputData) { + ArrayList> output = new ArrayList>(); + + PositionAwareInputStream progressIn = new PositionAwareInputStream( + inputData.getInputStream()); + // need to have access to the bufferedInput, so we can reuse it for the possible + // PGPObject chunks after the first one, e.g. files with several consecutive ASCII + // armour blocks + BufferedInputStream bufferedInput = new BufferedInputStream(progressIn); + try { + PGPKeyRing keyring = PGPConversionHelper.decodeKeyRing(bufferedInput); + while (keyring != null) { + String userId = PGPHelper.getMainUserId(keyring.getPublicKey()); + + String fingerprint = PGPHelper.convertFingerprintToHex(keyring.getPublicKey() + .getFingerprint()); + + Map attrs = new HashMap(); + attrs.put(MAP_ATTR_USER_ID, userId); + attrs.put(MAP_ATTR_FINGERPINT, mContext.getString(R.string.fingerprint) + "\n" + + fingerprint); + output.add(attrs); + + keyring = PGPConversionHelper.decodeKeyRing(bufferedInput); + } + } catch (Exception e) { + Log.e(Constants.TAG, "Exception", e); + } + + return output; + } + +} diff --git a/APG/src/org/thialfihar/android/apg/ui/widget/KeyListAdapter.java b/APG/src/org/thialfihar/android/apg/ui/widget/KeyListAdapter.java index 1f5c3a97e..194142b28 100644 --- a/APG/src/org/thialfihar/android/apg/ui/widget/KeyListAdapter.java +++ b/APG/src/org/thialfihar/android/apg/ui/widget/KeyListAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Dominik Schürmann + * Copyright (C) 2012-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. @@ -125,7 +125,7 @@ public class KeyListAdapter extends CursorTreeAdapter { if (userId == null) { Log.d(Constants.TAG, "userId is null!"); } - userId.setText(context.getString(R.string.fingerprint) + ":\n" + fingerprint); + userId.setText(context.getString(R.string.fingerprint) + "\n" + fingerprint); } else { // differentiate between keys and userIds in MergeCursor if (cursor.getColumnIndex(Keys.KEY_ID) != -1) { diff --git a/README.md b/README.md index 22708f8b5..07ca28f63 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al * IMPORT_FROM_FILE * IMPORT_FROM_QR_CODE * IMPORT_FROM_NFC +* SHARE_WITH_QR_CODE +* SHARE_WITH_NFC * EDIT_KEY * SELECT_PUBLIC_KEYS * SELECT_SECRET_KEY