Improved import with preview of keyrings

This commit is contained in:
Dominik Schürmann 2013-01-08 17:01:45 +01:00
parent 6cc7156fbd
commit 68039d3a8a
17 changed files with 451 additions and 183 deletions

View File

@ -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>

View File

@ -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 youll feel a vibration.</li>
<li>After it vibrates youll 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 persons device.</li>
<li>After it vibrates youll 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>

View File

@ -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>

View File

@ -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) {

View File

@ -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);

View File

@ -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 */

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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(

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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