diff options
17 files changed, 451 insertions, 183 deletions
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 @@ <LinearLayout android:id="@+id/import_from_qr_code_footer" - android:layout_width="fill_parent" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="vertical" @@ -36,23 +36,27 @@ </LinearLayout> <ScrollView - android:layout_width="fill_parent" - android:layout_height="fill_parent" + android:layout_width="match_parent" + android:layout_height="match_parent" android:layout_above="@id/import_from_qr_code_footer" android:fillViewport="true" > <LinearLayout - android:layout_width="fill_parent" + android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingLeft="10dp" - android:paddingRight="10dp" > + android:paddingLeft="12dp" + android:paddingRight="12dp" > - <TextView - android:id="@+id/import_from_qr_code_content" + <LinearLayout + android:id="@+id/import_keys_list_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="" /> + android:layout_marginTop="16dp" + android:orientation="vertical" + android:paddingLeft="4dp" + android:paddingRight="4dp" > + </LinearLayout> </LinearLayout> </ScrollView> 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 --> <ol> <li>Go to your partners 'Manage Public Keyrings' and long press on the keyring you want to share.</li> <li>Hold the two devices back to back (they have to be almost touching) and you’ll feel a vibration.</li> -<li>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.</li> -<li>Tap the card and the content will then load on the other person’s device.</li> +<li>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.</li> +<li>Tap the card and the content will then load on the your device.</li> </ol> </body> </html>
\ 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 @@ <string name="menu_importFromQrCode">Import from QR Code</string> <string name="menu_importFromNfc">Import from NFC</string> <string name="menu_exportKeys">Export All Keyrings</string> - <string name="menu_exportKey">Export Keyring</string> + <string name="menu_exportKey">Export To File</string> <string name="menu_deleteKey">Delete Keyring</string> <string name="menu_createKey">Create Keyring</string> <string name="menu_editKey">Edit Keyring</string> @@ -154,7 +154,7 @@ <string name="expired">expired</string> <string name="notValid">not valid</string> <string name="nKeyServers">%s key server(s)</string> - <string name="fingerprint">fingerprint</string> + <string name="fingerprint">Fingerprint:</string> <!-- choice_lowerCase: capitalized first word, no punctuation --> <string name="choice_none">None</string> @@ -232,6 +232,7 @@ <string name="qrScanImportSuccess">Successfully validated and imported keyring</string> <string name="listInformation">Long press one entry in this list to show more options!</string> <string name="listEmpty">This list is empty!</string> + <string name="nfcSuccessfull">Successfully sent keyring with NFC Beam!</string> <!-- error_lowerCase: phrases, no punctuation, all lowercase, @@ -266,6 +267,7 @@ <string name="error_onlyFilesAreSupported">Direct binary data without actual file in filesystem is not supported. This is only supported by ACTION_ENCRYPT_STREAM_AND_RETURN.</string> <string name="error_jellyBeanNeeded">You need Android 4.1 alias Jelly Bean to use Androids NFC Beam feature!</string> <string name="error_nfcNeeded">NFC is not available on your device!</string> + <string name="error_nothingImport">Nothing to import!</string> <!-- progress_lowerCase: lowercase, phrases, usually ending in '…' --> <string name="progress_done">done.</string> 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 <dominik@dominikschuermann.de> + * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + * + * 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<List<Map<String, String>>> { + 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<String, String> item = (Map<String, String>) 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<Map<String, String>> data = new ArrayList<Map<String, String>>(); + 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<List<Map<String, String>>> onCreateLoader(int id, Bundle args) { + return new ImportKeysListLoader(mActivity, mKeyringBytes, mImportFilename); + } + + @Override + public void onLoadFinished(Loader<List<Map<String, String>>> loader, + List<Map<String, String>> 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<String>(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<List<Map<String, String>>> 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<String> 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 <dominik@dominikschuermann.de> + * + * 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<List<Map<String, String>>> { + public static final String MAP_ATTR_USER_ID = "user_id"; + public static final String MAP_ATTR_FINGERPINT = "fingerprint"; + + Context mContext; + List<String> 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<Map<String, String>> 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<Map<String, String>> data) { + super.deliverResult(data); + } + + /** + * Similar to PGPMain.importKeyRings + * + * @param keyringBytes + * @return + */ + private ArrayList<Map<String, String>> generateListOfKeyrings(InputData inputData) { + ArrayList<Map<String, String>> output = new ArrayList<Map<String, String>>(); + + 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<String, String> attrs = new HashMap<String, String>(); + 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 <dominik@dominikschuermann.de> + * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> * * 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) { @@ -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 |