diff options
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter')
13 files changed, 514 insertions, 552 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java index 2ac19c1d9..5f2aec4fe 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java @@ -22,24 +22,25 @@ package org.sufficientlysecure.keychain.ui.adapter; * You can pass the result and an exception in it if an error occurred. * Concept found at: * https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader + * * @param <T> - Typ of the result which is wrapped */ -public class AsyncTaskResultWrapper <T>{ +public class AsyncTaskResultWrapper<T> { - private final T result; - private final Exception error; + private final T mResult; + private final Exception mError; - public AsyncTaskResultWrapper(T result, Exception error){ - this.result = result; - this.error = error; + public AsyncTaskResultWrapper(T result, Exception error) { + this.mResult = result; + this.mError = error; } public T getResult() { - return result; + return mResult; } public Exception getError() { - return error; + return mError; } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java new file mode 100644 index 000000000..a3ed08a4c --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui.adapter; + +import android.content.Context; +import android.database.Cursor; +import android.support.v4.widget.CursorAdapter; +import android.text.Spannable; +import android.text.style.ForegroundColorSpan; +import org.sufficientlysecure.keychain.R; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class HighlightQueryCursorAdapter extends CursorAdapter { + + private String mCurQuery; + + public HighlightQueryCursorAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + mCurQuery = null; + } + + public void setSearchQuery(String searchQuery) { + mCurQuery = searchQuery; + } + + public String getSearchQuery() { + return mCurQuery; + } + + protected Spannable highlightSearchQuery(String text) { + Spannable highlight = Spannable.Factory.getInstance().newSpannable(text); + + if (mCurQuery != null) { + Pattern pattern = Pattern.compile("(?i)" + mCurQuery); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + highlight.setSpan( + new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)), + matcher.start(), + matcher.end(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return highlight; + } else { + return highlight; + } + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 52186b662..7d3166af9 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -17,12 +17,6 @@ package org.sufficientlysecure.keychain.ui.adapter; -import java.util.ArrayList; -import java.util.List; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; - import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; @@ -37,11 +31,27 @@ import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; + +import java.util.ArrayList; +import java.util.List; + public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { protected LayoutInflater mInflater; protected Activity mActivity; - protected List<ImportKeysListEntry> data; + protected List<ImportKeysListEntry> mData; + + static class ViewHolder { + private TextView mainUserId; + private TextView mainUserIdRest; + private TextView keyId; + private TextView fingerprint; + private TextView algorithm; + private TextView status; + } public ImportKeysAdapter(Activity activity) { super(activity, -1); @@ -53,7 +63,7 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { public void setData(List<ImportKeysListEntry> data) { clear(); if (data != null) { - this.data = data; + this.mData = data; // add data to extended ArrayAdapter if (Build.VERSION.SDK_INT >= 11) { @@ -67,14 +77,15 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { } public List<ImportKeysListEntry> getData() { - return data; + return mData; } public ArrayList<ImportKeysListEntry> getSelectedData() { ArrayList<ImportKeysListEntry> selectedData = new ArrayList<ImportKeysListEntry>(); - for (ImportKeysListEntry entry : data) { - if (entry.isSelected()) + for (ImportKeysListEntry entry : mData) { + if (entry.isSelected()) { selectedData.add(entry); + } } return selectedData; } @@ -85,17 +96,21 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { } public View getView(int position, View convertView, ViewGroup parent) { - ImportKeysListEntry entry = data.get(position); - - View view = mInflater.inflate(R.layout.import_keys_list_entry, null); - - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - TextView keyId = (TextView) view.findViewById(R.id.keyId); - TextView fingerprint = (TextView) view.findViewById(R.id.fingerprint); - TextView algorithm = (TextView) view.findViewById(R.id.algorithm); - TextView status = (TextView) view.findViewById(R.id.status); - + ImportKeysListEntry entry = mData.get(position); + ViewHolder holder; + if (convertView == null) { + holder = new ViewHolder(); + convertView = mInflater.inflate(R.layout.import_keys_list_entry, null); + holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId); + holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest); + holder.keyId = (TextView) convertView.findViewById(R.id.keyId); + holder.fingerprint = (TextView) convertView.findViewById(R.id.fingerprint); + holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm); + holder.status = (TextView) convertView.findViewById(R.id.status); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } // main user id String userId = entry.userIds.get(0); String[] userIdSplit = PgpKeyHelper.splitUserId(userId); @@ -105,39 +120,40 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { // show red user id if it is a secret key if (entry.secretKey) { userIdSplit[0] = mActivity.getString(R.string.secret_key) + " " + userIdSplit[0]; - mainUserId.setTextColor(Color.RED); + holder.mainUserId.setTextColor(Color.RED); } - mainUserId.setText(userIdSplit[0]); + holder.mainUserId.setText(userIdSplit[0]); } else { - mainUserId.setText(R.string.user_id_no_name); + holder.mainUserId.setText(R.string.user_id_no_name); } // email if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); - mainUserIdRest.setVisibility(View.VISIBLE); + holder.mainUserIdRest.setText(userIdSplit[1]); + holder.mainUserIdRest.setVisibility(View.VISIBLE); } else { - mainUserIdRest.setVisibility(View.GONE); + holder.mainUserIdRest.setVisibility(View.GONE); } - keyId.setText(entry.hexKeyId); + holder.keyId.setText(entry.keyIdHex); - if (entry.fingerPrint != null) { - fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint); - fingerprint.setVisibility(View.VISIBLE); + if (entry.fingerPrintHex != null) { + holder.fingerprint.setText(PgpKeyHelper.colorizeFingerprint(entry.fingerPrintHex)); + holder.fingerprint.setVisibility(View.VISIBLE); } else { - fingerprint.setVisibility(View.GONE); + holder.fingerprint.setVisibility(View.GONE); } - algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); + holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); if (entry.revoked) { - status.setText(R.string.revoked); + holder.status.setText(R.string.revoked); } else { - status.setVisibility(View.GONE); + holder.status.setVisibility(View.GONE); } - LinearLayout ll = (LinearLayout) view.findViewById(R.id.list); + LinearLayout ll = (LinearLayout) convertView.findViewById(R.id.list); + ll.removeAllViews(); if (entry.userIds.size() == 1) { ll.setVisibility(View.GONE); } else { @@ -162,10 +178,10 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { } } - CheckBox cBox = (CheckBox) view.findViewById(R.id.selected); + CheckBox cBox = (CheckBox) convertView.findViewById(R.id.selected); cBox.setChecked(entry.isSelected()); - return view; + return convertView; } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java index 4a7a9c93a..9b20effc2 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java @@ -19,11 +19,7 @@ package org.sufficientlysecure.keychain.ui.adapter; import android.os.Parcel; import android.os.Parcelable; - -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; +import android.util.SparseArray; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPPublicKey; @@ -33,35 +29,40 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; + public class ImportKeysListEntry implements Serializable, Parcelable { private static final long serialVersionUID = -7797972103284992662L; - public ArrayList<String> userIds; + public ArrayList<String> userIds; public long keyId; + public String keyIdHex; public boolean revoked; public Date date; // TODO: not displayed - public String fingerPrint; - public String hexKeyId; + public String fingerPrintHex; public int bitStrength; public String algorithm; public boolean secretKey; - private boolean selected; + private boolean mSelected; - private byte[] bytes = new byte[]{}; + private byte[] mBytes = new byte[]{}; public ImportKeysListEntry(ImportKeysListEntry b) { this.userIds = b.userIds; this.keyId = b.keyId; this.revoked = b.revoked; this.date = b.date; - this.fingerPrint = b.fingerPrint; - this.hexKeyId = b.hexKeyId; + this.fingerPrintHex = b.fingerPrintHex; + this.keyIdHex = b.keyIdHex; this.bitStrength = b.bitStrength; this.algorithm = b.algorithm; this.secretKey = b.secretKey; - this.selected = b.selected; - this.bytes = b.bytes; + this.mSelected = b.mSelected; + this.mBytes = b.mBytes; } public int describeContents() { @@ -74,14 +75,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable { dest.writeLong(keyId); dest.writeByte((byte) (revoked ? 1 : 0)); dest.writeSerializable(date); - dest.writeString(fingerPrint); - dest.writeString(hexKeyId); + dest.writeString(fingerPrintHex); + dest.writeString(keyIdHex); dest.writeInt(bitStrength); dest.writeString(algorithm); dest.writeByte((byte) (secretKey ? 1 : 0)); - dest.writeByte((byte) (selected ? 1 : 0)); - dest.writeInt(bytes.length); - dest.writeByteArray(bytes); + dest.writeByte((byte) (mSelected ? 1 : 0)); + dest.writeInt(mBytes.length); + dest.writeByteArray(mBytes); } public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() { @@ -92,14 +93,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.keyId = source.readLong(); vr.revoked = source.readByte() == 1; vr.date = (Date) source.readSerializable(); - vr.fingerPrint = source.readString(); - vr.hexKeyId = source.readString(); + vr.fingerPrintHex = source.readString(); + vr.keyIdHex = source.readString(); vr.bitStrength = source.readInt(); vr.algorithm = source.readString(); vr.secretKey = source.readByte() == 1; - vr.selected = source.readByte() == 1; - vr.bytes = new byte[source.readInt()]; - source.readByteArray(vr.bytes); + vr.mSelected = source.readByte() == 1; + vr.mBytes = new byte[source.readInt()]; + source.readByteArray(vr.mBytes); return vr; } @@ -109,34 +110,105 @@ public class ImportKeysListEntry implements Serializable, Parcelable { } }; - public long getKeyId() { - return keyId; + public String getKeyIdHex() { + return keyIdHex; } public byte[] getBytes() { - return bytes; + return mBytes; } public void setBytes(byte[] bytes) { - this.bytes = bytes; + this.mBytes = bytes; + } + + public boolean isSelected() { + return mSelected; + } + + public void setSelected(boolean selected) { + this.mSelected = selected; + } + + public long getKeyId() { + return keyId; + } + + public void setKeyId(long keyId) { + this.keyId = keyId; + } + + public void setKeyIdHex(String keyIdHex) { + this.keyIdHex = keyIdHex; + } + + public boolean isRevoked() { + return revoked; + } + + public void setRevoked(boolean revoked) { + this.revoked = revoked; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getFingerPrintHex() { + return fingerPrintHex; + } + + public void setFingerPrintHex(String fingerPrintHex) { + this.fingerPrintHex = fingerPrintHex; + } + + public int getBitStrength() { + return bitStrength; + } + + public void setBitStrength(int bitStrength) { + this.bitStrength = bitStrength; + } + + public String getAlgorithm() { + return algorithm; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public boolean isSecretKey() { + return secretKey; + } + + public void setSecretKey(boolean secretKey) { + this.secretKey = secretKey; + } + + public ArrayList<String> getUserIds() { + return userIds; + } + + public void setUserIds(ArrayList<String> userIds) { + this.userIds = userIds; } /** * Constructor for later querying from keyserver */ public ImportKeysListEntry() { + // keys from keyserver are always public keys secretKey = false; + // do not select by default + mSelected = false; userIds = new ArrayList<String>(); } - public boolean isSelected() { - return selected; - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - /** * Constructor based on key object, used for import from NFC, QR Codes, files */ @@ -144,13 +216,13 @@ public class ImportKeysListEntry implements Serializable, Parcelable { public ImportKeysListEntry(PGPKeyRing pgpKeyRing) { // save actual key object into entry, used to import it later try { - this.bytes = pgpKeyRing.getEncoded(); + this.mBytes = pgpKeyRing.getEncoded(); } catch (IOException e) { Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e); } // selected is default - this.selected = true; + this.mSelected = true; if (pgpKeyRing instanceof PGPSecretKeyRing) { secretKey = true; @@ -162,27 +234,39 @@ public class ImportKeysListEntry implements Serializable, Parcelable { for (String userId : new IterableIterator<String>(pgpKeyRing.getPublicKey().getUserIDs())) { userIds.add(userId); } + this.keyId = pgpKeyRing.getPublicKey().getKeyID(); + this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId); this.revoked = pgpKeyRing.getPublicKey().isRevoked(); - this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() - .getFingerprint(), true); - this.hexKeyId = "0x" + PgpKeyHelper.convertKeyIdToHex(keyId); + this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() + .getFingerprint()); this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength(); - int algorithm = pgpKeyRing.getPublicKey().getAlgorithm(); - if (algorithm == PGPPublicKey.RSA_ENCRYPT || algorithm == PGPPublicKey.RSA_GENERAL - || algorithm == PGPPublicKey.RSA_SIGN) { - this.algorithm = "RSA"; - } else if (algorithm == PGPPublicKey.DSA) { - this.algorithm = "DSA"; - } else if (algorithm == PGPPublicKey.ELGAMAL_ENCRYPT - || algorithm == PGPPublicKey.ELGAMAL_GENERAL) { - this.algorithm = "ElGamal"; - } else if (algorithm == PGPPublicKey.EC || algorithm == PGPPublicKey.ECDSA) { - this.algorithm = "ECC"; - } else { - // TODO: with resources - this.algorithm = "unknown"; - } + final int algorithm = pgpKeyRing.getPublicKey().getAlgorithm(); + this.algorithm = getAlgorithmFromId(algorithm); + } + + /** + * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a> + */ + private final static SparseArray<String> ALGORITHM_IDS = new SparseArray<String>() {{ + put(-1, "unknown"); // TODO: with resources + put(0, "unencrypted"); + put(PGPPublicKey.RSA_GENERAL, "RSA"); + put(PGPPublicKey.RSA_ENCRYPT, "RSA"); + put(PGPPublicKey.RSA_SIGN, "RSA"); + put(PGPPublicKey.ELGAMAL_ENCRYPT, "ElGamal"); + put(PGPPublicKey.ELGAMAL_GENERAL, "ElGamal"); + put(PGPPublicKey.DSA, "DSA"); + put(PGPPublicKey.EC, "ECC"); + put(PGPPublicKey.ECDSA, "ECC"); + put(PGPPublicKey.ECDH, "ECC"); + }}; + + /** + * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a> + */ + public static String getAlgorithmFromId(int algorithmId) { + return (ALGORITHM_IDS.get(algorithmId) != null ? ALGORITHM_IDS.get(algorithmId) : ALGORITHM_IDS.get(-1)); } -}
\ No newline at end of file +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 76649b27b..c9983213c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -17,11 +17,8 @@ package org.sufficientlysecure.keychain.ui.adapter; -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - +import android.content.Context; +import android.support.v4.content.AsyncTaskLoader; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPUtil; @@ -30,16 +27,35 @@ import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.PositionAwareInputStream; -import android.content.Context; -import android.support.v4.content.AsyncTaskLoader; +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.util.ArrayList; + +public class ImportKeysListLoader + extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { + + public static class FileHasNoContent extends Exception { + + } + + public static class NonPgpPart extends Exception { + private int mCount; + + public NonPgpPart(int count) { + this.mCount = count; + } + + public int getCount() { + return mCount; + } + } -public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { Context mContext; InputData mInputData; - ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>(); - AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper; + ArrayList<ImportKeysListEntry> mData = new ArrayList<ImportKeysListEntry>(); + AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper; public ImportKeysListLoader(Context context, InputData inputData) { super(context); @@ -50,16 +66,16 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper @Override public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { - entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, null); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, null); if (mInputData == null) { Log.e(Constants.TAG, "Input data is null!"); - return entryListWrapper; + return mEntryListWrapper; } generateListOfKeyrings(mInputData); - return entryListWrapper; + return mEntryListWrapper; } @Override @@ -87,11 +103,15 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper /** * Reads all PGPKeyRing objects from input - * - * @param keyringBytes + * + * @param inputData * @return */ private void generateListOfKeyrings(InputData inputData) { + + boolean isEmpty = true; + int nonPgpCounter = 0; + PositionAwareInputStream progressIn = new PositionAwareInputStream( inputData.getInputStream()); @@ -103,6 +123,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper // read all available blocks... (asc files can contain many blocks with BEGIN END) while (bufferedInput.available() > 0) { + isEmpty = false; InputStream in = PGPUtil.getDecoderStream(bufferedInput); PGPObjectFactory objectFactory = new PGPObjectFactory(in); @@ -116,17 +137,31 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper addToData(newKeyring); } else { Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); + nonPgpCounter++; } } } } catch (Exception e) { Log.e(Constants.TAG, "Exception on parsing key file!", e); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, e); + nonPgpCounter = 0; + } + + if (isEmpty) { + Log.e(Constants.TAG, "File has no content!", new FileHasNoContent()); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> + (mData, new FileHasNoContent()); + } + + if (nonPgpCounter > 0) { + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> + (mData, new NonPgpPart(nonPgpCounter)); } } private void addToData(PGPKeyRing keyring) { ImportKeysListEntry item = new ImportKeysListEntry(keyring); - data.add(item); + mData.add(item); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java index 3a3b6e58b..a4dd06e40 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui.adapter; import android.content.Context; import android.support.v4.content.AsyncTaskLoader; - import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.KeyServer; @@ -27,14 +26,15 @@ import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; -public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { +public class ImportKeysListServerLoader + extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { Context mContext; String mServerQuery; String mKeyServer; - private ArrayList<ImportKeysListEntry> entryList = new ArrayList<ImportKeysListEntry>(); - private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper; + private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<ImportKeysListEntry>(); + private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper; public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) { super(context); @@ -46,16 +46,16 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW @Override public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { - entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null); if (mServerQuery == null) { Log.e(Constants.TAG, "mServerQuery is null!"); - return entryListWrapper; + return mEntryListWrapper; } queryServer(mServerQuery, mKeyServer); - return entryListWrapper; + return mEntryListWrapper; } @Override @@ -89,18 +89,19 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW try { ArrayList<ImportKeysListEntry> searchResult = server.search(query); + mEntryList.clear(); // add result to data - entryList.addAll(searchResult); - entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null); + mEntryList.addAll(searchResult); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null); } catch (KeyServer.InsufficientQuery e) { Log.e(Constants.TAG, "InsufficientQuery", e); - entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e); } catch (KeyServer.QueryException e) { Log.e(Constants.TAG, "QueryException", e); - entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e); } catch (KeyServer.TooManyResponses e) { Log.e(Constants.TAG, "TooManyResponses", e); - entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); + mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java deleted file mode 100644 index ac505adfb..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import java.util.HashMap; -import java.util.Set; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.util.Log; - -import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.database.Cursor; -import android.graphics.Color; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; -import android.widget.TextView; - -/** - * Implements StickyListHeadersAdapter from library - */ -public class KeyListPublicAdapter extends CursorAdapter implements StickyListHeadersAdapter { - private LayoutInflater mInflater; - private int mSectionColumnIndex; - private int mIndexUserId; - private int mIndexIsRevoked; - - @SuppressLint("UseSparseArrays") - private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>(); - - public KeyListPublicAdapter(Context context, Cursor c, int flags, int sectionColumnIndex) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - mSectionColumnIndex = sectionColumnIndex; - initIndex(c); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - - return super.swapCursor(newCursor); - } - - /** - * Get column indexes for performance reasons just once in constructor and swapCursor. For a - * performance comparison see http://stackoverflow.com/a/17999582 - * - * @param cursor - */ - private void initIndex(Cursor cursor) { - if (cursor != null) { - mIndexUserId = cursor.getColumnIndexOrThrow(KeychainContract.UserIds.USER_ID); - mIndexIsRevoked = cursor.getColumnIndexOrThrow(KeychainContract.Keys.IS_REVOKED); - } - } - - /** - * Bind cursor data to the item list view - * <p/> - * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. Thus - * no ViewHolder is required here. - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - TextView revoked = (TextView) view.findViewById(R.id.revoked); - - String userId = cursor.getString(mIndexUserId); - String[] userIdSplit = PgpKeyHelper.splitUserId(userId); - if (userIdSplit[0] != null) { - mainUserId.setText(userIdSplit[0]); - } else { - mainUserId.setText(R.string.user_id_no_name); - } - if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); - mainUserIdRest.setVisibility(View.VISIBLE); - } else { - mainUserIdRest.setVisibility(View.GONE); - } - - boolean isRevoked = cursor.getInt(mIndexIsRevoked) > 0; - if (isRevoked) { - revoked.setVisibility(View.VISIBLE); - } else { - revoked.setVisibility(View.GONE); - } - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_public_item, null); - } - - /** - * Creates a new header view and binds the section headers to it. It uses the ViewHolder - * pattern. Most functionality is similar to getView() from Android's CursorAdapter. - * <p/> - * NOTE: The variables mDataValid and mCursor are available due to the super class - * CursorAdapter. - */ - @Override - public View getHeaderView(int position, View convertView, ViewGroup parent) { - HeaderViewHolder holder; - if (convertView == null) { - holder = new HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.key_list_public_header, parent, false); - holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); - convertView.setTag(holder); - } else { - holder = (HeaderViewHolder) convertView.getTag(); - } - - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return convertView; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - // set header text as first char in user id - String userId = mCursor.getString(mSectionColumnIndex); - String headerText = convertView.getResources().getString(R.string.user_id_no_name); - if (userId != null && userId.length() > 0) { - headerText = "" + mCursor.getString(mSectionColumnIndex).subSequence(0, 1).charAt(0); - } - holder.text.setText(headerText); - return convertView; - } - - /** - * Header IDs should be static, position=1 should always return the same Id that is. - */ - @Override - public long getHeaderId(int position) { - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return -1; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - // return the first character of the name as ID because this is what - // headers are based upon - String userId = mCursor.getString(mSectionColumnIndex); - if (userId != null && userId.length() > 0) { - return userId.subSequence(0, 1).charAt(0); - } else { - return Long.MAX_VALUE; - } - } - - class HeaderViewHolder { - TextView text; - } - - /** - * -------------------------- MULTI-SELECTION METHODS -------------- - */ - public void setNewSelection(int position, boolean value) { - mSelection.put(position, value); - notifyDataSetChanged(); - } - - public boolean isPositionChecked(int position) { - Boolean result = mSelection.get(position); - return result == null ? false : result; - } - - public Set<Integer> getCurrentCheckedPosition() { - return mSelection.keySet(); - } - - public void removeSelection(int position) { - mSelection.remove(position); - notifyDataSetChanged(); - } - - public void clearSelection() { - mSelection.clear(); - notifyDataSetChanged(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - // let the adapter handle setting up the row views - View v = super.getView(position, convertView, parent); - - /** - * Change color for multi-selection - */ - // default color - v.setBackgroundColor(Color.TRANSPARENT); - if (mSelection.get(position) != null && mSelection.get(position).booleanValue()) { - // this is a selected position, change color! - v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); - } - return v; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java deleted file mode 100644 index 11d1e8c17..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -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; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.database.Cursor; -import android.graphics.Color; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -public class KeyListSecretAdapter extends CursorAdapter { - private LayoutInflater mInflater; - - private int mIndexUserId; - - @SuppressLint("UseSparseArrays") - private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>(); - - public KeyListSecretAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - initIndex(c); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - - return super.swapCursor(newCursor); - } - - /** - * Get column indexes for performance reasons just once in constructor and swapCursor. For a - * performance comparison see http://stackoverflow.com/a/17999582 - * - * @param cursor - */ - private void initIndex(Cursor cursor) { - if (cursor != null) { - mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID); - } - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - - String userId = cursor.getString(mIndexUserId); - String[] userIdSplit = PgpKeyHelper.splitUserId(userId); - - if (userIdSplit[0] != null) { - mainUserId.setText(userIdSplit[0]); - } else { - mainUserId.setText(R.string.user_id_no_name); - } - if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); - } else { - mainUserIdRest.setText(""); - } - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_secret_item, null); - } - - /** -------------------------- MULTI-SELECTION METHODS -------------- */ - public void setNewSelection(int position, boolean value) { - mSelection.put(position, value); - notifyDataSetChanged(); - } - - public boolean isPositionChecked(int position) { - Boolean result = mSelection.get(position); - return result == null ? false : result; - } - - public Set<Integer> getCurrentCheckedPosition() { - return mSelection.keySet(); - } - - public void removeSelection(int position) { - mSelection.remove(position); - notifyDataSetChanged(); - } - - public void clearSelection() { - mSelection.clear(); - notifyDataSetChanged(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - // let the adapter handle setting up the row views - View v = super.getView(position, convertView, parent); - - /** - * Change color for multi-selection - */ - // default color - v.setBackgroundColor(Color.TRANSPARENT); - if (mSelection.get(position) != null) { - // this is a selected position, change color! - v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); - } - return v; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java index 78f7b1f7e..c997599bd 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java @@ -17,15 +17,11 @@ package org.sufficientlysecure.keychain.ui.adapter; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; - import android.content.Context; import android.widget.ArrayAdapter; +import java.util.*; + public class KeyValueSpinnerAdapter extends ArrayAdapter<String> { private final HashMap<Integer, String> mData; private final int[] mKeys; @@ -98,4 +94,4 @@ public class KeyValueSpinnerAdapter extends ArrayAdapter<String> { } return -1; } -}
\ No newline at end of file +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index d44dd5890..fbbb9caa4 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -17,23 +17,22 @@ package org.sufficientlysecure.keychain.ui.adapter; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; - import android.content.Context; import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.ListView; import android.widget.TextView; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -public class SelectKeyCursorAdapter extends CursorAdapter { + +public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter { protected int mKeyType; @@ -45,17 +44,16 @@ public class SelectKeyCursorAdapter extends CursorAdapter { private int mIndexProjectionValid; private int mIndexProjectionAvailable; - public final static String PROJECTION_ROW_AVAILABLE = "available"; - public final static String PROJECTION_ROW_VALID = "valid"; + public static final String PROJECTION_ROW_AVAILABLE = "available"; + public static final String PROJECTION_ROW_VALID = "valid"; public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView, - int keyType) { + int keyType) { super(context, c, flags); mInflater = LayoutInflater.from(context); mListView = listView; mKeyType = keyType; - initIndex(c); } @@ -69,7 +67,7 @@ public class SelectKeyCursorAdapter extends CursorAdapter { /** * Get column indexes for performance reasons just once in constructor and swapCursor. For a * performance comparison see http://stackoverflow.com/a/17999582 - * + * * @param cursor */ private void initIndex(Cursor cursor) { @@ -104,12 +102,12 @@ public class SelectKeyCursorAdapter extends CursorAdapter { String[] userIdSplit = PgpKeyHelper.splitUserId(userId); if (userIdSplit[0] != null) { - mainUserId.setText(userIdSplit[0]); + mainUserId.setText(highlightSearchQuery(userIdSplit[0])); } else { mainUserId.setText(R.string.user_id_no_name); } if (userIdSplit[1] != null) { - mainUserIdRest.setText(userIdSplit[1]); + mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); } else { mainUserIdRest.setText(""); } @@ -117,7 +115,7 @@ public class SelectKeyCursorAdapter extends CursorAdapter { // TODO: needed to key id to no? keyId.setText(R.string.no_key); long masterKeyId = cursor.getLong(mIndexMasterKeyId); - keyId.setText(PgpKeyHelper.convertKeyIdToHex(masterKeyId)); + keyId.setText(PgpKeyHelper.convertKeyIdToHexShort(masterKeyId)); // TODO: needed to set unknown_status? status.setText(R.string.unknown_status); @@ -164,5 +162,4 @@ public class SelectKeyCursorAdapter extends CursorAdapter { public View newView(Context context, Cursor cursor, ViewGroup parent) { return mInflater.inflate(R.layout.select_key_item, null); } - } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java index 924a70897..f435d46ef 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + package org.sufficientlysecure.keychain.ui.adapter; import android.content.Context; @@ -19,12 +36,12 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar. private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); static final class TabInfo { - private final Class<?> clss; - private final Bundle args; + private final Class<?> mClss; + private final Bundle mArgs; - TabInfo(Class<?> _class, Bundle _args) { - clss = _class; - args = _args; + TabInfo(Class<?> mClss, Bundle mArgs) { + this.mClss = mClss; + this.mArgs = mArgs; } } @@ -54,7 +71,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar. @Override public Fragment getItem(int position) { TabInfo info = mTabs.get(position); - return Fragment.instantiate(mContext, info.clss.getName(), info.args); + return Fragment.instantiate(mContext, info.mClss.getName(), info.mArgs); } public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { @@ -81,4 +98,4 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar. public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { } -}
\ No newline at end of file +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java index 54c7eb60e..9d60c1530 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java @@ -17,18 +17,23 @@ package org.sufficientlysecure.keychain.ui.adapter; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; - import android.content.Context; +import android.content.res.ColorStateList; import android.database.Cursor; +import android.graphics.Color; import android.support.v4.widget.CursorAdapter; +import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; + +import java.util.Date; public class ViewKeyKeysAdapter extends CursorAdapter { private LayoutInflater mInflater; @@ -40,6 +45,10 @@ public class ViewKeyKeysAdapter extends CursorAdapter { private int mIndexCanCertify; private int mIndexCanEncrypt; private int mIndexCanSign; + private int mIndexRevokedKey; + private int mIndexExpiry; + + private ColorStateList mDefaultTextColor; public ViewKeyKeysAdapter(Context context, Cursor c, int flags) { super(context, c, flags); @@ -59,7 +68,7 @@ public class ViewKeyKeysAdapter extends CursorAdapter { /** * Get column indexes for performance reasons just once in constructor and swapCursor. For a * performance comparison see http://stackoverflow.com/a/17999582 - * + * * @param cursor */ private void initIndex(Cursor cursor) { @@ -71,6 +80,8 @@ public class ViewKeyKeysAdapter extends CursorAdapter { mIndexCanCertify = cursor.getColumnIndexOrThrow(Keys.CAN_CERTIFY); mIndexCanEncrypt = cursor.getColumnIndexOrThrow(Keys.CAN_ENCRYPT); mIndexCanSign = cursor.getColumnIndexOrThrow(Keys.CAN_SIGN); + mIndexRevokedKey = cursor.getColumnIndexOrThrow(Keys.IS_REVOKED); + mIndexExpiry = cursor.getColumnIndexOrThrow(Keys.EXPIRY); } } @@ -78,17 +89,18 @@ public class ViewKeyKeysAdapter extends CursorAdapter { public void bindView(View view, Context context, Cursor cursor) { TextView keyId = (TextView) view.findViewById(R.id.keyId); TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails); + TextView keyExpiry = (TextView) view.findViewById(R.id.keyExpiry); ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey); ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey); ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); + ImageView revokedKeyIcon = (ImageView) view.findViewById(R.id.ic_revokedKey); - String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); + String keyIdStr = PgpKeyHelper.convertKeyIdToHexShort(cursor.getLong(mIndexKeyId)); String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm), cursor.getInt(mIndexKeySize)); keyId.setText(keyIdStr); - keyDetails.setText("(" + algorithmStr + ")"); if (cursor.getInt(mIndexIsMasterKey) != 1) { @@ -114,11 +126,52 @@ public class ViewKeyKeysAdapter extends CursorAdapter { } else { signIcon.setVisibility(View.VISIBLE); } + + boolean valid = true; + if (cursor.getInt(mIndexRevokedKey) > 0) { + revokedKeyIcon.setVisibility(View.VISIBLE); + + valid = false; + } else { + keyId.setTextColor(mDefaultTextColor); + keyDetails.setTextColor(mDefaultTextColor); + keyExpiry.setTextColor(mDefaultTextColor); + + revokedKeyIcon.setVisibility(View.GONE); + } + + if (!cursor.isNull(mIndexExpiry)) { + Date expiryDate = new Date(cursor.getLong(mIndexExpiry) * 1000); + + valid = valid && expiryDate.after(new Date()); + keyExpiry.setText("(" + + context.getString(R.string.label_expiry) + ": " + + DateFormat.getDateFormat(context).format(expiryDate) + ")"); + + keyExpiry.setVisibility(View.VISIBLE); + } + else { + keyExpiry.setVisibility(View.GONE); + } + // if key is expired or revoked, strike through text + if (!valid) { + keyId.setText(OtherHelper.strikeOutText(keyId.getText())); + keyDetails.setText(OtherHelper.strikeOutText(keyDetails.getText())); + keyExpiry.setText(OtherHelper.strikeOutText(keyExpiry.getText())); + } + keyId.setEnabled(valid); + keyDetails.setEnabled(valid); + keyExpiry.setEnabled(valid); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.view_key_keys_item, null); + View view = mInflater.inflate(R.layout.view_key_keys_item, null); + if (mDefaultTextColor == null) { + TextView keyId = (TextView) view.findViewById(R.id.keyId); + mDefaultTextColor = keyId.getTextColors(); + } + return view; } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java index cf8699417..61572b9ce 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java @@ -17,33 +17,54 @@ package org.sufficientlysecure.keychain.ui.adapter; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; - import android.content.Context; import android.database.Cursor; import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.TextView; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; + +import java.util.ArrayList; public class ViewKeyUserIdsAdapter extends CursorAdapter { private LayoutInflater mInflater; - private int mIndexUserId; + private int mIndexUserId, mIndexRank; - public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags) { + final private ArrayList<Boolean> mCheckStates; + + public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) { super(context, c, flags); mInflater = LayoutInflater.from(context); + mCheckStates = showCheckBoxes ? new ArrayList<Boolean>() : null; + initIndex(c); } + public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags) { + this(context, c, flags, false); + } @Override public Cursor swapCursor(Cursor newCursor) { initIndex(newCursor); + if(mCheckStates != null) { + mCheckStates.clear(); + if(newCursor != null) { + int count = newCursor.getCount(); + mCheckStates.ensureCapacity(count); + // initialize to true (use case knowledge: we usually want to sign all uids) + for(int i = 0; i < count; i++) + mCheckStates.add(true); + } + } return super.swapCursor(newCursor); } @@ -51,26 +72,73 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter { /** * Get column indexes for performance reasons just once in constructor and swapCursor. For a * performance comparison see http://stackoverflow.com/a/17999582 - * + * * @param cursor */ private void initIndex(Cursor cursor) { if (cursor != null) { mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID); + mIndexRank = cursor.getColumnIndexOrThrow(UserIds.RANK); } } @Override public void bindView(View view, Context context, Cursor cursor) { - String userIdStr = cursor.getString(mIndexUserId); - TextView userId = (TextView) view.findViewById(R.id.userId); - userId.setText(userIdStr); + TextView vRank = (TextView) view.findViewById(R.id.rank); + TextView vUserId = (TextView) view.findViewById(R.id.userId); + TextView vAddress = (TextView) view.findViewById(R.id.address); + + vRank.setText(Integer.toString(cursor.getInt(mIndexRank))); + + String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexUserId)); + if (userId[0] != null) { + vUserId.setText(userId[0]); + } else { + vUserId.setText(R.string.user_id_no_name); + } + vAddress.setText(userId[1]); + + // don't care further if checkboxes aren't shown + if(mCheckStates == null) + return; + + final CheckBox vCheckBox = (CheckBox) view.findViewById(R.id.checkBox); + final int position = cursor.getPosition(); + vCheckBox.setClickable(false); + vCheckBox.setChecked(mCheckStates.get(position)); + vCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + mCheckStates.set(position, b); + } + }); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + vCheckBox.toggle(); + } + }); + + } + + public ArrayList<String> getSelectedUserIds() { + ArrayList<String> result = new ArrayList<String>(); + for(int i = 0; i < mCheckStates.size(); i++) { + if(mCheckStates.get(i)) { + mCursor.moveToPosition(i); + result.add(mCursor.getString(mIndexUserId)); + } + } + return result; } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.view_key_userids_item, null); + View view = mInflater.inflate(R.layout.view_key_userids_item, null); + // only need to do this once ever, since mShowCheckBoxes is final + view.findViewById(R.id.checkBox).setVisibility(mCheckStates != null ? View.VISIBLE : View.GONE); + return view; } } |