mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
Merge pull request #395 from uberspot/master
Remove duplicate code from ActionBarHelper. Add export in multiselect.
This commit is contained in:
commit
a9e5619a14
@ -50,6 +50,7 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
|
||||
<!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->
|
||||
<application
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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 the keyType is secret get the PGPSecretKeyRing
|
||||
// based on the row id and encode it to the output
|
||||
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));
|
||||
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 if it's a public key get the PGPPublicKeyRing
|
||||
// and encode that to the output
|
||||
} 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));
|
||||
updateProgress(i * 100 / rowIdsSize, 100);
|
||||
PGPPublicKeyRing publicKeyRing =
|
||||
ProviderHelper.getPGPPublicKeyRingByRowId(mContext, keyRingRowIds.get(i));
|
||||
|
||||
if (publicKeyRing != null) {
|
||||
publicKeyRing.encode(outPub);
|
||||
publicKeyRing.encode(arOutStream);
|
||||
}
|
||||
}
|
||||
outPub.close();
|
||||
}
|
||||
|
||||
returnData.putInt(KeychainIntentService.RESULT_EXPORT, keyRingMasterKeyIds.size());
|
||||
arOutStream.close();
|
||||
}
|
||||
|
||||
returnData.putInt(KeychainIntentService.RESULT_EXPORT, rowIdsSize);
|
||||
|
||||
updateProgress(R.string.progress_done, 100, 100);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -1,27 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:dividerPadding="12dp"
|
||||
android:orientation="horizontal"
|
||||
android:divider="@drawable/abc_list_divider_holo_light"
|
||||
android:showDividers="end" >
|
||||
|
||||
<include layout="@layout/actionbar_include_save_button" />
|
||||
|
||||
</LinearLayout>
|
@ -1,29 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:dividerPadding="12dp"
|
||||
android:divider="@drawable/abc_list_divider_holo_light"
|
||||
android:orientation="horizontal"
|
||||
android:showDividers="middle">
|
||||
|
||||
<include layout="@layout/actionbar_include_cancel_button" />
|
||||
|
||||
<include layout="@layout/actionbar_include_save_button" />
|
||||
|
||||
</LinearLayout>
|
@ -1,36 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/actionbar_save"
|
||||
style="@style/Widget.AppCompat.ActionButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/actionbar_save_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:drawableLeft="@drawable/ic_action_save"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingRight="20dp"
|
||||
style="@style/Widget.AppCompat.Light.ActionBar.TabText"
|
||||
android:text="Save (set in-code!)" />
|
||||
|
||||
</FrameLayout>
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
@ -49,7 +49,7 @@
|
||||
android:paddingRight="5dip"
|
||||
android:text="@string/label_email" />
|
||||
|
||||
<EditText
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
|
@ -5,6 +5,10 @@
|
||||
android:id="@+id/menu_key_list_public_multi_select_all"
|
||||
android:icon="@drawable/ic_action_select_all"
|
||||
android:title="@string/menu_select_all" />
|
||||
<item
|
||||
android:id="@+id/menu_key_list_public_multi_export"
|
||||
android:icon="@drawable/ic_action_import_export"
|
||||
android:title="@string/menu_export_key" />
|
||||
<item
|
||||
android:id="@+id/menu_key_list_public_multi_encrypt"
|
||||
android:icon="@drawable/ic_action_secure"
|
||||
|
@ -5,6 +5,10 @@
|
||||
android:id="@+id/menu_key_list_public_multi_select_all"
|
||||
android:icon="@drawable/ic_action_select_all"
|
||||
android:title="@string/menu_select_all" />
|
||||
<item
|
||||
android:id="@+id/menu_key_list_public_multi_export"
|
||||
android:icon="@drawable/ic_action_import_export"
|
||||
android:title="@string/menu_export_key" />
|
||||
<item
|
||||
android:id="@+id/menu_key_list_public_multi_delete"
|
||||
android:icon="@drawable/ic_action_discard"
|
||||
|
@ -155,6 +155,14 @@ See http://source.android.com/source/code-style.html
|
||||
|
||||
See http://www.androidpolice.com/2009/11/04/auto-formatting-android-xml-files-with-eclipse/
|
||||
|
||||
### Automated syntax check with CheckStyle
|
||||
* Paste the tools/checkstyle.xml file to ~/.AndroidStudioPreview/config/codestyles/ (in Linux/Unix)
|
||||
or ~/Library/Preferences/AndroidStudioPreview/codestyles (in Mac OSX)
|
||||
* Go to Settings (or Preferences in Mac OS X) > Code Style > Java, select OpenPgpChecker,
|
||||
as well as Code Style > XML and select OpenPgpChecker again.
|
||||
* Start code inspection and see the results by selecting Analyze > Inspect Code from Android-Studio
|
||||
or you can directly run checkstyle via cli with .tools/checkstyle. Make sure it's executable first.
|
||||
|
||||
## Licenses
|
||||
OpenPGP Kechain is licensed under GPLv3+.
|
||||
Some parts (older parts and some libraries are Apache License v2, MIT X11 License)
|
||||
|
1
tools/checkstyle
Executable file
1
tools/checkstyle
Executable file
@ -0,0 +1 @@
|
||||
checkstyle -c tools/checkstyle.xml -r OpenPGP-Keychain/src/main/java 2>&1 | egrep -v 'log4j'
|
356
tools/checkstyle.xml
Normal file
356
tools/checkstyle.xml
Normal file
@ -0,0 +1,356 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!-- This is a checkstyle configuration file. For descriptions of
|
||||
what the following rules do, please see the checkstyle configuration
|
||||
page at http://checkstyle.sourceforge.net/config.html -->
|
||||
|
||||
<module name="OpenPgpChecker">
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="tools/suppressions.xml"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<!-- Requires a copyright notice in each file.
|
||||
Code intended to be open-sourced may have a multi-line copyright
|
||||
notice, so that this required text appears on the second line:
|
||||
<pre>
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* (details of open-source license...)
|
||||
</pre>
|
||||
-->
|
||||
<property name="format"
|
||||
value="^(//| \*) Copyright (\([cC]\) )?[\d]{4}(\-[\d]{4})? .*$"/>
|
||||
<property name="minimum" value="1"/>
|
||||
<property name="maximum" value="10"/>
|
||||
<property name="message" value="Copyright is missing or malformed."/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="FileTabCharacter">
|
||||
<!-- Checks that there are no tab characters in the file.
|
||||
-->
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<!-- Checks that FIXME is not used in comments. TODO is preferred.
|
||||
-->
|
||||
<property name="format" value="((//.*)|(\*.*))FIXME"/>
|
||||
<property name="message" value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."'/>
|
||||
</module>
|
||||
|
||||
<!--
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="((//.*)|(\*.*))TODO[^(]"/>
|
||||
<property name="message" value='All TODOs should be named. e.g. "TODO(johndoe): Refactor when v2 is released."'/>
|
||||
</module>
|
||||
-->
|
||||
|
||||
<!-- All Java AST specific tests live under TreeWalker module. -->
|
||||
<module name="TreeWalker">
|
||||
|
||||
<!--
|
||||
|
||||
IMPORT CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="RedundantImport">
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="UnusedImports">
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="ImportOrder">
|
||||
<!-- Checks for out of order import statements. -->
|
||||
|
||||
<property name="severity" value="warning"/>
|
||||
<property name="groups" value="com.google,android,junit,com,net,org,se,java,javax"/>
|
||||
<!-- This ensures that static imports go first. -->
|
||||
<property name="option" value="top"/>
|
||||
<property name="tokens" value="STATIC_IMPORT, IMPORT"/>
|
||||
</module>
|
||||
|
||||
<!--
|
||||
|
||||
JAVADOC CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<!--
|
||||
<module name="JavadocMethod">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="severity" value="warning"/>
|
||||
<property name="allowMissingJavadoc" value="true"/>
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
<property name="allowMissingThrowsTags" value="true"/>
|
||||
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||
<property name="allowUndeclaredRTE" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocType">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocStyle">
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
-->
|
||||
|
||||
<!--
|
||||
|
||||
NAMING CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<!-- Item 38 - Adhere to generally accepted naming conventions -->
|
||||
|
||||
<module name="PackageName">
|
||||
<!-- Validates identifiers for package names against the
|
||||
supplied expression. -->
|
||||
<!-- Here the default checkstyle rule restricts package name parts to
|
||||
seven characters, this is not in line with common practice at Google.
|
||||
-->
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="TypeNameCheck">
|
||||
<!-- Validates static, final fields against the
|
||||
expression "^[A-Z][a-zA-Z0-9]*$". -->
|
||||
<metadata name="altname" value="TypeName"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="ConstantNameCheck">
|
||||
<!-- Validates non-private, static, final fields against the supplied
|
||||
public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
|
||||
<metadata name="altname" value="ConstantName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="false"/>
|
||||
<property name="format" value="^([A-Z_][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="StaticVariableNameCheck">
|
||||
<!-- Validates static, non-final fields against the supplied
|
||||
expression "^[a-z][a-zA-Z0-9]*_?$". -->
|
||||
<metadata name="altname" value="StaticVariableName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="true"/>
|
||||
<property name="format" value="^s[A-Z][a-zA-Z0-9]*_?$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="MemberNameCheck">
|
||||
<!-- Validates non-static members against the supplied expression. -->
|
||||
<metadata name="altname" value="MemberName"/>
|
||||
<property name="applyToPublic" value="false"/>
|
||||
<property name="applyToProtected" value="true"/>
|
||||
<property name="applyToPackage" value="true"/>
|
||||
<property name="applyToPrivate" value="true"/>
|
||||
<property name="format" value="^m[A-Z][a-zA-Z0-9]*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="MemberNameCheck">
|
||||
<!-- Validates non-static members against the supplied expression. -->
|
||||
<metadata name="altname" value="MemberName"/>
|
||||
<property name="applyToPublic" value="true"/>
|
||||
<property name="applyToProtected" value="false"/>
|
||||
<property name="applyToPackage" value="false"/>
|
||||
<property name="applyToPrivate" value="false"/>
|
||||
<property name="format" value="^[a-z]([^A-Z]|$)[a-zA-Z0-9]*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="MethodNameCheck">
|
||||
<!-- Validates identifiers for method names. -->
|
||||
<metadata name="altname" value="MethodName"/>
|
||||
<property name="format" value="^[a-z]([^A-Z]|$)[a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="ParameterName">
|
||||
<!-- Validates identifiers for method parameters against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalFinalVariableName">
|
||||
<!-- Validates identifiers for local final variables against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalVariableName">
|
||||
<!-- Validates identifiers for local variables against the
|
||||
expression "^[a-z][a-zA-Z0-9]*$". -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
LENGTH and CODING CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="LineLength">
|
||||
<!-- Checks if a line is too long. -->
|
||||
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="110"/>
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<!--
|
||||
The default ignore pattern exempts the following elements:
|
||||
- import statements
|
||||
- long URLs inside comments
|
||||
-->
|
||||
|
||||
<property name="ignorePattern"
|
||||
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
|
||||
default="^(package .*;\s*)|(import .*;\s*)|( *\* *https?://.*)$"/>
|
||||
</module>
|
||||
|
||||
<module name="LeftCurly">
|
||||
<!-- Checks for placement of the left curly brace ('{'). -->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="RightCurly">
|
||||
<!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
|
||||
the same line. e.g., the following example is fine:
|
||||
<pre>
|
||||
if {
|
||||
...
|
||||
} else
|
||||
</pre>
|
||||
-->
|
||||
<!-- This next example is not fine:
|
||||
<pre>
|
||||
if {
|
||||
...
|
||||
}
|
||||
else
|
||||
</pre>
|
||||
-->
|
||||
<property name="option" value="same"/>
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<!-- Checks for braces around if and else blocks -->
|
||||
<module name="NeedBraces">
|
||||
<property name="severity" value="warning"/>
|
||||
<property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
|
||||
</module>
|
||||
|
||||
<module name="UpperEll">
|
||||
<!-- Checks that long constants are defined with an upper ell.-->
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="FallThrough">
|
||||
<!-- Warn about falling through to the next case statement. Similar to
|
||||
javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
|
||||
on the last non-blank line preceding the fallen-into case contains 'fall through' (or
|
||||
some other variants which we don't publicized to promote consistency).
|
||||
-->
|
||||
<property name="reliefPattern"
|
||||
value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
MODIFIERS CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="ModifierOrder">
|
||||
<!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
|
||||
8.4.3. The prescribed order is:
|
||||
public, protected, private, abstract, static, final, transient, volatile,
|
||||
synchronized, native, strictfp
|
||||
-->
|
||||
</module>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
WHITESPACE CHECKS
|
||||
|
||||
-->
|
||||
|
||||
<module name="WhitespaceAround">
|
||||
<!-- Checks that various tokens are surrounded by whitespace.
|
||||
This includes most binary operators and keywords followed
|
||||
by regular or curly braces.
|
||||
-->
|
||||
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
|
||||
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
|
||||
EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
|
||||
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
|
||||
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
|
||||
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
|
||||
SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="WhitespaceAfter">
|
||||
<!-- Checks that commas, semicolons and typecasts are followed by
|
||||
whitespace.
|
||||
-->
|
||||
<property name="tokens" value="COMMA, SEMI, TYPECAST"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceAfter">
|
||||
<!-- Checks that there is no whitespace after various unary operators.
|
||||
Linebreaks are allowed.
|
||||
-->
|
||||
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
|
||||
UNARY_PLUS"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceBefore">
|
||||
<!-- Checks that there is no whitespace before various unary operators.
|
||||
Linebreaks are allowed.
|
||||
-->
|
||||
<property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
<property name="severity" value="error"/>
|
||||
</module>
|
||||
|
||||
<module name="ParenPad">
|
||||
<!-- Checks that there is no whitespace before close parens or after
|
||||
open parens.
|
||||
-->
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
</module>
|
||||
|
Loading…
Reference in New Issue
Block a user