Merge pull request #395 from uberspot/master

Remove duplicate code from ActionBarHelper. Add export in multiselect.
This commit is contained in:
Dominik Schürmann
2014-03-12 16:23:22 +01:00
41 changed files with 608 additions and 280 deletions

View File

@@ -43,6 +43,8 @@ public final class Constants {
public static final class path {
public static final String APP_DIR = Environment.getExternalStorageDirectory()
+ "/OpenPGP-Keychain";
public static final String APP_DIR_FILE_SEC = APP_DIR + "/secexport.asc";
public static final String APP_DIR_FILE_PUB = APP_DIR + "/pubexport.asc";
}
public static final class pref {

View File

@@ -56,28 +56,33 @@ public class ActionBarHelper {
* Sets custom view on ActionBar for Done/Cancel activities
*
* @param actionBar
* @param doneText
* @param doneOnClickListener
* @param cancelText
* @param cancelOnClickListener
* @param firstText
* @param firstDrawableId
* @param firstOnClickListener
* @param secondText
* @param secondDrawableId
* @param secondOnClickListener
*/
public static void setDoneCancelView(ActionBar actionBar, int doneText,
OnClickListener doneOnClickListener, int cancelText,
OnClickListener cancelOnClickListener) {
public static void setTwoButtonView(ActionBar actionBar, int firstText, int firstDrawableId,
OnClickListener firstOnClickListener, int secondText, int secondDrawableId,
OnClickListener secondOnClickListener) {
// Inflate a "Done"/"Cancel" custom action bar view
// Inflate the custom action bar view
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater.inflate(
R.layout.actionbar_custom_view_done_cancel, null);
((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)).setText(doneText);
TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text));
firstTextView.setText(firstText);
firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0);
customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener(
doneOnClickListener);
((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text))
.setText(cancelText);
firstOnClickListener);
TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text));
secondTextView.setText(secondText);
secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0);
customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener(
cancelOnClickListener);
secondOnClickListener);
// Show the custom action bar view and hide the normal Home icon and title.
actionBar.setDisplayShowTitleEnabled(false);
@@ -91,20 +96,22 @@ public class ActionBarHelper {
* Sets custom view on ActionBar for Done activities
*
* @param actionBar
* @param doneText
* @param doneOnClickListener
* @param firstText
* @param firstOnClickListener
*/
public static void setDoneView(ActionBar actionBar, int doneText,
OnClickListener doneOnClickListener) {
public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId,
OnClickListener firstOnClickListener) {
// Inflate a "Done" custom action bar view to serve as the "Up" affordance.
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater
.inflate(R.layout.actionbar_custom_view_done, null);
((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)).setText(doneText);
TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text));
firstTextView.setText(firstText);
firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0);
customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener(
doneOnClickListener);
firstOnClickListener);
// Show the custom action bar view and hide the normal Home icon and title.
actionBar.setDisplayShowTitleEnabled(false);
@@ -112,65 +119,4 @@ public class ActionBarHelper {
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(customActionBarView);
}
/**
* Sets custom view on ActionBar for Save activities
*
* @param actionBar
* @param saveText
* @param saveOnClickListener
*/
public static void setSaveView(ActionBar actionBar, int saveText,
OnClickListener saveOnClickListener) {
// Inflate a "Save" custom action bar view to serve as the "Up" affordance.
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater
.inflate(R.layout.actionbar_custom_view_save, null);
((TextView) customActionBarView.findViewById(R.id.actionbar_save_text)).setText(saveText);
customActionBarView.findViewById(R.id.actionbar_save).setOnClickListener(
saveOnClickListener);
// Show the custom action bar view and hide the normal Home icon and title.
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(customActionBarView);
}
/**
* Sets custom view on ActionBar for Save/Cancel activities
*
* @param actionBar
* @param saveText
* @param saveOnClickListener
* @param cancelText
* @param cancelOnClickListener
*/
public static void setSaveCancelView(ActionBar actionBar, int saveText,
OnClickListener saveOnClickListener, int cancelText,
OnClickListener cancelOnClickListener) {
// Inflate a "Done"/"Cancel" custom action bar view
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater.inflate(
R.layout.actionbar_custom_view_save_cancel, null);
((TextView) customActionBarView.findViewById(R.id.actionbar_save_text)).setText(saveText);
customActionBarView.findViewById(R.id.actionbar_save).setOnClickListener(
saveOnClickListener);
((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text))
.setText(cancelText);
customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener(
cancelOnClickListener);
// Show the custom action bar view and hide the normal Home icon and title.
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2014 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.sufficientlysecure.keychain.helper;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.util.Patterns;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ContactHelper {
public static final List<String> getMailAccounts(Context context) {
final Account[] accounts = AccountManager.get(context).getAccounts();
final Set<String> emailSet = new HashSet<String>();
for (Account account : accounts) {
if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
emailSet.add(account.name);
}
}
return new ArrayList<String>(emailSet);
}
}

View File

@@ -20,7 +20,6 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
@@ -63,7 +62,7 @@ public class ExportHelper {
/**
* Show dialog where to export keys
*/
public void showExportKeysDialog(final Uri dataUri, final int keyType,
public void showExportKeysDialog(final long[] rowIds, final int keyType,
final String exportFilename) {
mExportFilename = exportFilename;
@@ -75,7 +74,7 @@ public class ExportHelper {
Bundle data = message.getData();
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
exportKeys(dataUri, keyType);
exportKeys(rowIds, keyType);
}
}
};
@@ -86,7 +85,7 @@ public class ExportHelper {
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
public void run() {
String title = null;
if (dataUri == null) {
if (rowIds == null) {
// export all keys
title = activity.getString(R.string.title_export_keys);
} else {
@@ -112,7 +111,7 @@ public class ExportHelper {
/**
* Export keys
*/
public void exportKeys(Uri dataUri, int keyType) {
public void exportKeys(long[] rowIds, int keyType) {
Log.d(Constants.TAG, "exportKeys started");
// Send all information needed to service to export key in other thread
@@ -126,13 +125,10 @@ public class ExportHelper {
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType);
if (dataUri == null) {
if (rowIds == null) {
data.putBoolean(KeychainIntentService.EXPORT_ALL, true);
} else {
// TODO: put data uri into service???
long keyRingMasterKeyId = ProviderHelper.getMasterKeyId(activity, dataUri);
data.putLong(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, keyRingMasterKeyId);
data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_ROW_ID, rowIds);
}
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);

View File

@@ -144,8 +144,8 @@ public class Preferences {
Constants.defaults.KEY_SERVERS);
Vector<String> servers = new Vector<String>();
String chunks[] = rawData.split(",");
for (int i = 0; i < chunks.length; ++i) {
String tmp = chunks[i].trim();
for (String c : chunks) {
String tmp = c.trim();
if (tmp.length() > 0) {
servers.add(tmp);
}
@@ -156,8 +156,8 @@ public class Preferences {
public void setKeyServers(String[] value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
String rawData = "";
for (int i = 0; i < value.length; ++i) {
String tmp = value[i].trim();
for (String v : value) {
String tmp = v.trim();
if (tmp.length() == 0) {
continue;
}

View File

@@ -193,11 +193,10 @@ public class PgpHelper {
* @param context
* @param progress
* @param file
* @throws FileNotFoundException
* @throws IOException
*/
public static void deleteFileSecurely(Context context, ProgressDialogUpdater progress, File file)
throws FileNotFoundException, IOException {
throws IOException {
long length = file.length();
SecureRandom random = new SecureRandom();
RandomAccessFile raf = new RandomAccessFile(file, "rws");

View File

@@ -79,8 +79,9 @@ public class PgpImportExport {
public boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = new ArmoredOutputStream(bos);
ArmoredOutputStream aos = null;
try {
aos = new ArmoredOutputStream(bos);
aos.write(keyring.getEncoded());
aos.close();
@@ -95,7 +96,8 @@ public class PgpImportExport {
return false;
} finally {
try {
bos.close();
if (aos != null) aos.close();
if (bos != null) bos.close();
} catch (IOException e) {
}
}
@@ -155,59 +157,53 @@ public class PgpImportExport {
return returnData;
}
public Bundle exportKeyRings(ArrayList<Long> keyRingMasterKeyIds, int keyType,
OutputStream outStream) throws PgpGeneralException, FileNotFoundException,
public Bundle exportKeyRings(ArrayList<Long> keyRingRowIds, int keyType,
OutputStream outStream) throws PgpGeneralException,
PGPException, IOException {
Bundle returnData = new Bundle();
int rowIdsSize = keyRingRowIds.size();
updateProgress(
mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
keyRingMasterKeyIds.size()), 0, 100);
rowIdsSize), 0, 100);
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new PgpGeneralException(
mContext.getString(R.string.error_external_storage_not_ready));
}
// For each row id
for (int i = 0; i < rowIdsSize; ++i) {
// Create an output stream
ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext));
if (keyType == Id.type.secret_key) {
ArmoredOutputStream outSec = new ArmoredOutputStream(outStream);
outSec.setHeader("Version", PgpHelper.getFullVersion(mContext));
for (int i = 0; i < keyRingMasterKeyIds.size(); ++i) {
updateProgress(i * 100 / keyRingMasterKeyIds.size() / 2, 100);
PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(
mContext, keyRingMasterKeyIds.get(i));
// If the keyType is secret get the PGPSecretKeyRing
// based on the row id and encode it to the output
if (keyType == Id.type.secret_key) {
updateProgress(i * 100 / rowIdsSize / 2, 100);
PGPSecretKeyRing secretKeyRing =
ProviderHelper.getPGPSecretKeyRingByRowId(mContext, keyRingRowIds.get(i));
if (secretKeyRing != null) {
secretKeyRing.encode(outSec);
secretKeyRing.encode(arOutStream);
}
}
outSec.close();
} else {
// export public keyrings...
ArmoredOutputStream outPub = new ArmoredOutputStream(outStream);
outPub.setHeader("Version", PgpHelper.getFullVersion(mContext));
for (int i = 0; i < keyRingMasterKeyIds.size(); ++i) {
// double the needed time if exporting both public and secret parts
if (keyType == Id.type.secret_key) {
updateProgress(i * 100 / keyRingMasterKeyIds.size() / 2, 100);
} else {
updateProgress(i * 100 / keyRingMasterKeyIds.size(), 100);
}
PGPPublicKeyRing publicKeyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId(
mContext, keyRingMasterKeyIds.get(i));
// Else if it's a public key get the PGPPublicKeyRing
// and encode that to the output
} else {
updateProgress(i * 100 / rowIdsSize, 100);
PGPPublicKeyRing publicKeyRing =
ProviderHelper.getPGPPublicKeyRingByRowId(mContext, keyRingRowIds.get(i));
if (publicKeyRing != null) {
publicKeyRing.encode(outPub);
publicKeyRing.encode(arOutStream);
}
}
outPub.close();
arOutStream.close();
}
returnData.putInt(KeychainIntentService.RESULT_EXPORT, keyRingMasterKeyIds.size());
returnData.putInt(KeychainIntentService.RESULT_EXPORT, rowIdsSize);
updateProgress(R.string.progress_done, 100, 100);

View File

@@ -190,7 +190,7 @@ public class PgpKeyOperation {
}
public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase,
String newPassPhrase) throws IOException, PGPException, PGPException,
String newPassPhrase) throws IOException, PGPException,
NoSuchProviderException {
updateProgress(R.string.progress_building_key, 0, 100);

View File

@@ -404,6 +404,30 @@ public class ProviderHelper {
return masterKeyIds;
}
/**
* Private helper method
*/
private static ArrayList<Long> getKeyRingsRowIds(Context context, Uri queryUri) {
Cursor cursor = context.getContentResolver().query(queryUri,
new String[]{KeyRings._ID}, null, null, null);
ArrayList<Long> rowIds = new ArrayList<Long>();
if (cursor != null) {
int IdCol = cursor.getColumnIndex(KeyRings._ID);
if (cursor.moveToFirst()) {
do {
rowIds.add(cursor.getLong(IdCol));
} while (cursor.moveToNext());
}
}
if (cursor != null) {
cursor.close();
}
return rowIds;
}
/**
* Retrieves ids of all SecretKeyRings
*/
@@ -420,6 +444,22 @@ public class ProviderHelper {
return getKeyRingsMasterKeyIds(context, queryUri);
}
/**
* Retrieves ids of all SecretKeyRings
*/
public static ArrayList<Long> getSecretKeyRingsRowIds(Context context) {
Uri queryUri = KeyRings.buildSecretKeyRingsUri();
return getKeyRingsRowIds(context, queryUri);
}
/**
* Retrieves ids of all PublicKeyRings
*/
public static ArrayList<Long> getPublicKeyRingsRowIds(Context context) {
Uri queryUri = KeyRings.buildPublicKeyRingsUri();
return getKeyRingsRowIds(context, queryUri);
}
public static void deletePublicKeyRing(Context context, long rowId) {
ContentResolver cr = context.getContentResolver();
cr.delete(KeyRings.buildPublicKeyRingsUri(Long.toString(rowId)), null, null);

View File

@@ -50,6 +50,7 @@ import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
@@ -153,6 +154,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String EXPORT_KEY_TYPE = "export_key_type";
public static final String EXPORT_ALL = "export_all";
public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id";
public static final String EXPORT_KEY_RING_ROW_ID = "export_key_rind_row_id";
// upload key
public static final String UPLOAD_KEY_SERVER = "upload_key_server";
@@ -675,10 +677,12 @@ public class KeychainIntentService extends IntentService implements ProgressDial
String outputFile = data.getString(EXPORT_FILENAME);
long[] rowIds = new long[0];
// If not exporting all keys get the rowIds of the keys to export from the intent
boolean exportAll = data.getBoolean(EXPORT_ALL);
long keyRingMasterKeyId = -1;
if (!exportAll) {
keyRingMasterKeyId = data.getLong(EXPORT_KEY_RING_MASTER_KEY_ID);
rowIds = data.getLongArray(EXPORT_KEY_RING_ROW_ID);
}
/* Operation */
@@ -691,24 +695,26 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// OutputStream
FileOutputStream outStream = new FileOutputStream(outputFile);
ArrayList<Long> keyRingMasterKeyIds = new ArrayList<Long>();
ArrayList<Long> keyRingRowIds = new ArrayList<Long>();
if (exportAll) {
// get all key ring row ids based on export type
// get all key ring row ids based on export type
if (keyType == Id.type.public_key) {
keyRingMasterKeyIds = ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
keyRingRowIds = ProviderHelper.getPublicKeyRingsRowIds(this);
} else {
keyRingMasterKeyIds = ProviderHelper.getSecretKeyRingsMasterKeyIds(this);
keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this);
}
} else {
keyRingMasterKeyIds.add(keyRingMasterKeyId);
for(long rowId : rowIds) {
keyRingRowIds.add(rowId);
}
}
Bundle resultData = new Bundle();
Bundle resultData;
PgpImportExport pgpImportExport = new PgpImportExport(this, this);
resultData = pgpImportExport
.exportKeyRings(keyRingMasterKeyIds, keyType, outStream);
.exportKeyRings(keyRingRowIds, keyType, outStream);
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {

View File

@@ -21,6 +21,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import android.util.LongSparseArray;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -77,7 +78,7 @@ public class PassphraseCacheService extends Service {
private BroadcastReceiver mIntentReceiver;
private HashMap<Long, String> mPassphraseCache = new HashMap<Long, String>();
private LongSparseArray<String> mPassphraseCache = new LongSparseArray<String>();
Context mContext;
@@ -347,7 +348,7 @@ public class PassphraseCacheService extends Service {
Log.d(TAG, "Timeout of keyId " + keyId + ", removed from memory!");
// stop whole service if no cached passphrases remaining
if (mPassphraseCache.isEmpty()) {
if (mPassphraseCache.size() == 0) {
Log.d(TAG, "No passphrases remaining in memory, stopping service!");
stopSelf();
}

View File

@@ -41,7 +41,7 @@ public class AppSettingsActivity extends ActionBarActivity {
super.onCreate(savedInstanceState);
// Inflate a "Done" custom action bar
ActionBarHelper.setDoneView(getSupportActionBar(), R.string.api_settings_save,
ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.api_settings_save, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {

View File

@@ -88,7 +88,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
// Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow,
ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.api_register_allow, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -108,7 +108,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.finish();
}
}
}, R.string.api_register_disallow, new View.OnClickListener() {
}, R.string.api_register_disallow, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// Disallow
@@ -161,7 +161,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
}
// Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay,
ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -173,7 +173,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.setResult(RESULT_OK, resultData);
RemoteServiceActivity.this.finish();
}
}, R.string.btn_do_not_save, new View.OnClickListener() {
}, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel
@@ -214,7 +214,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
String text = "<font color=\"red\">" + errorMessage + "</font>";
// Inflate a "Done" custom action bar view
ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay,
ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override

View File

@@ -530,6 +530,10 @@ public class DecryptActivity extends DrawerActivity {
Log.e(Constants.TAG, "File not found!", e);
AppMsg.makeText(this, getString(R.string.error_file_not_found, e.getMessage()),
AppMsg.STYLE_ALERT).show();
} finally {
try {
if (inStream != null) inStream.close();
} catch (Exception e){ }
}
} else {
inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes());

View File

@@ -134,14 +134,14 @@ public class EditKeyActivity extends ActionBarActivity {
* @param intent
*/
private void handleActionCreateKey(Intent intent) {
// Inflate a "Done"/"Cancel" custom action bar
ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_save,
// Inflate a "Save"/"Cancel" custom action bar
ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_save, R.drawable.ic_action_save,
new View.OnClickListener() {
@Override
public void onClick(View v) {
saveClicked();
}
}, R.string.btn_do_not_save, new View.OnClickListener() {
}, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
cancelClicked();
@@ -249,8 +249,8 @@ public class EditKeyActivity extends ActionBarActivity {
* @param intent
*/
private void handleActionEditKey(Intent intent) {
// Inflate a "Done"/"Cancel" custom action bar
ActionBarHelper.setSaveView(getSupportActionBar(), R.string.btn_save,
// Inflate a "Save"/"Cancel" custom action bar
ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_save, R.drawable.ic_action_save,
new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -329,8 +329,8 @@ public class EditKeyActivity extends ActionBarActivity {
cancelClicked();
return true;
case R.id.menu_key_edit_export_file:
mExportHelper.showExportKeysDialog(mDataUri, Id.type.secret_key, Constants.path.APP_DIR
+ "/secexport.asc");
long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())};
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.path.APP_DIR_FILE_SEC);
return true;
case R.id.menu_key_edit_delete: {
// Message is received after key is deleted

View File

@@ -59,8 +59,7 @@ public class KeyListPublicActivity extends DrawerActivity {
return true;
case R.id.menu_key_list_public_export:
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR
+ "/pubexport.asc");
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB);
return true;
default:

View File

@@ -18,10 +18,11 @@
package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import java.util.Set;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
@@ -47,6 +48,7 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.text.TextUtils;
import android.view.ActionMode;
@@ -179,6 +181,11 @@ public class KeyListPublicFragment extends Fragment implements SearchView.OnQuer
encrypt(mode, ids);
break;
}
case R.id.menu_key_list_public_multi_export: {
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
mExportHelper.showExportKeysDialog(ids, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB);
break;
}
case R.id.menu_key_list_public_multi_delete: {
showDeleteKeyDialog(mode, ids);
break;

View File

@@ -62,8 +62,7 @@ public class KeyListSecretActivity extends DrawerActivity {
return true;
case R.id.menu_key_list_secret_export:
mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.path.APP_DIR
+ "/secexport.asc");
mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.path.APP_DIR_FILE_SEC);
return true;
case R.id.menu_key_list_secret_import:

View File

@@ -17,10 +17,10 @@
package org.sufficientlysecure.keychain.ui;
import java.util.Set;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
@@ -41,6 +41,7 @@ import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.ActionBarActivity;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
@@ -106,6 +107,12 @@ public class KeyListSecretFragment extends ListFragment implements
}
break;
}
case R.id.menu_key_list_public_multi_export: {
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.path.APP_DIR_FILE_SEC);
break;
}
}
return true;
}

View File

@@ -50,14 +50,14 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
super.onCreate(savedInstanceState);
// Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay,
ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
// ok
okClicked();
}
}, R.string.btn_do_not_save, new View.OnClickListener() {
}, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel
@@ -81,11 +81,11 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
Intent intent = getIntent();
String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS);
if (servers != null) {
for (int i = 0; i < servers.length; ++i) {
for (String serv : servers) {
KeyServerEditor view = (KeyServerEditor) mInflater.inflate(
R.layout.key_server_editor, mEditors, false);
view.setEditorListener(this);
view.setValue(servers[i]);
view.setValue(serv);
mEditors.addView(view);
}
}

View File

@@ -46,14 +46,14 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
super.onCreate(savedInstanceState);
// Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay,
ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@Override
public void onClick(View v) {
// ok
okClicked();
}
}, R.string.btn_do_not_save, new View.OnClickListener() {
}, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel

View File

@@ -199,8 +199,8 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
if (masterKeyIds != null) {
for (int i = 0; i < getListView().getCount(); ++i) {
long keyId = mAdapter.getMasterKeyId(i);
for (int j = 0; j < masterKeyIds.length; ++j) {
if (keyId == masterKeyIds[j]) {
for (long masterKeyId : masterKeyIds) {
if (keyId == masterKeyId) {
getListView().setItemChecked(i, true);
break;
}

View File

@@ -118,8 +118,8 @@ public class ViewKeyActivity extends ActionBarActivity {
uploadToKeyserver(mDataUri);
return true;
case R.id.menu_key_view_export_file:
mExportHelper.showExportKeysDialog(mDataUri, Id.type.public_key, Constants.path.APP_DIR
+ "/pubexport.asc");
long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())};
mExportHelper.showExportKeysDialog(ids, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB);
return true;
case R.id.menu_key_view_share_default_fingerprint:
shareKey(mDataUri, true);

View File

@@ -280,13 +280,14 @@ public class ViewKeyMainFragment extends Fragment implements
// for each 4 characters of the fingerprint + 1 space
for (int i = 0; i < fingerprint.length(); i += 5) {
String fourChars = fingerprint.substring(i, Math.min(i + 4, fingerprint.length()));
int minFingLength = Math.min(i + 4, fingerprint.length());
String fourChars = fingerprint.substring(i, minFingLength);
// Create a foreground color by converting the 4 fingerprint chars to an int hashcode
// and then converting that int to hex to use as a color
fcs = new ForegroundColorSpan(
Color.parseColor(String.format("#%06X", (0xFFFFFF & fourChars.hashCode()))));
sb.setSpan(fcs, i, Math.min(i+4, fingerprint.length()), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(fcs, i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
return sb;

View File

@@ -18,8 +18,6 @@
package org.sufficientlysecure.keychain.ui.adapter;
import java.util.HashMap;
import java.util.Set;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;

View File

@@ -18,7 +18,6 @@
package org.sufficientlysecure.keychain.ui.adapter;
import java.util.HashMap;
import java.util.Set;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;

View File

@@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Choice;
import java.util.ArrayList;
import java.util.Vector;
public class CreateKeyDialogFragment extends DialogFragment {
@@ -78,7 +79,7 @@ public class CreateKeyDialogFragment extends DialogFragment {
boolean wouldBeMasterKey = (childCount == 0);
final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm);
Vector<Choice> choices = new Vector<Choice>();
ArrayList<Choice> choices = new ArrayList<Choice>();
choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString(
R.string.dsa)));
if (!wouldBeMasterKey) {

View File

@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui.widget;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.widget.*;
import org.sufficientlysecure.keychain.R;
import android.content.Context;
@@ -26,11 +27,9 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.helper.ContactHelper;
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null;
@@ -38,7 +37,7 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
private BootstrapButton mDeleteButton;
private RadioButton mIsMainUserId;
private EditText mName;
private EditText mEmail;
private AutoCompleteTextView mEmail;
private EditText mComment;
// see http://www.regular-expressions.info/email.html
@@ -102,9 +101,17 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
mIsMainUserId.setOnClickListener(this);
mName = (EditText) findViewById(R.id.name);
mEmail = (EditText) findViewById(R.id.email);
mEmail = (AutoCompleteTextView) findViewById(R.id.email);
mComment = (EditText) findViewById(R.id.comment);
mEmail.setThreshold(1); // Start working from first character
mEmail.setAdapter(
new ArrayAdapter<String>
(this.getContext(), android.R.layout.simple_dropdown_item_1line,
ContactHelper.getMailAccounts(getContext())
));
super.onFinishInflate();
}