diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-01-27 14:18:25 +0100 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-01-27 14:18:25 +0100 |
commit | cb3ca37db9c5c3da05df804979e99628fff6f7b0 (patch) | |
tree | d32bd573bdd0cbbcde68a562a48915e95386ba4d /OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter | |
parent | 08e57019b092d8abcd443a6801cc040d46403021 (diff) | |
download | open-keychain-cb3ca37db9c5c3da05df804979e99628fff6f7b0.tar.gz open-keychain-cb3ca37db9c5c3da05df804979e99628fff6f7b0.tar.bz2 open-keychain-cb3ca37db9c5c3da05df804979e99628fff6f7b0.zip |
New Gradle project structure
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter')
9 files changed, 1219 insertions, 0 deletions
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 new file mode 100644 index 000000000..41539d0f8 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -0,0 +1,159 @@ +/* + * 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.List; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.TextView; + +public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { + protected LayoutInflater mInflater; + protected Activity mActivity; + + protected List<ImportKeysListEntry> data; + + public ImportKeysAdapter(Activity activity) { + super(activity, -1); + mActivity = activity; + mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @SuppressLint("NewApi") + public void setData(List<ImportKeysListEntry> data) { + clear(); + if (data != null) { + this.data = data; + + // add data to extended ArrayAdapter + if (Build.VERSION.SDK_INT >= 11) { + addAll(data); + } else { + for (ImportKeysListEntry entry : data) { + add(entry); + } + } + } + } + + public List<ImportKeysListEntry> getData() { + return data; + } + + @Override + public boolean hasStableIds() { + return true; + } + + 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); + mainUserId.setText(R.string.unknown_user_id); + TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); + mainUserIdRest.setText(""); + TextView keyId = (TextView) view.findViewById(R.id.keyId); + keyId.setText(R.string.no_key); + TextView fingerprint = (TextView) view.findViewById(R.id.fingerprint); + TextView algorithm = (TextView) view.findViewById(R.id.algorithm); + algorithm.setText(""); + TextView status = (TextView) view.findViewById(R.id.status); + status.setText(""); + + String userId = entry.userIds.get(0); + if (userId != null) { + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); + + if (userIdSplit[0] != null && userIdSplit[0].length() > 0) { + // show red user id if it is a secret key + if (entry.secretKey) { + userId = mActivity.getString(R.string.secret_key) + " " + userId; + mainUserId.setTextColor(Color.RED); + } else { + mainUserId.setText(userIdSplit[0]); + } + } + + if (userIdSplit[1] != null && userIdSplit[1].length() > 0) { + mainUserIdRest.setText(userIdSplit[1]); + mainUserIdRest.setVisibility(View.VISIBLE); + } else { + mainUserIdRest.setVisibility(View.GONE); + } + + } + + keyId.setText(entry.hexKeyId); + fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint); + + algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); + + if (entry.revoked) { + status.setText("revoked"); + } else { + status.setVisibility(View.GONE); + } + + LinearLayout ll = (LinearLayout) view.findViewById(R.id.list); + if (entry.userIds.size() == 1) { + ll.setVisibility(View.GONE); + } else { + boolean first = true; + boolean second = true; + for (String uid : entry.userIds) { + if (first) { + first = false; + continue; + } + if (!second) { + View sep = new View(mActivity); + sep.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 1)); + sep.setBackgroundResource(android.R.drawable.divider_horizontal_dark); + ll.addView(sep); + } + TextView uidView = (TextView) mInflater.inflate( + R.layout.import_keys_list_entry_user_id, null); + uidView.setText(uid); + ll.addView(uidView); + second = false; + } + } + + CheckBox cBox = (CheckBox) view.findViewById(R.id.selected); + cBox.setChecked(entry.isSelected()); + + return view; + } + +} 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 new file mode 100644 index 000000000..1a100a585 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java @@ -0,0 +1,105 @@ +/* + * 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.io.Serializable; +import java.util.ArrayList; + +import org.spongycastle.openpgp.PGPKeyRing; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.util.AlgorithmNames; +import org.sufficientlysecure.keychain.util.IterableIterator; + +public class ImportKeysListEntry implements Serializable { + private static final long serialVersionUID = -7797972103284992662L; + public ArrayList<String> userIds; + public long keyId; + + public boolean revoked; + // public Date date; + public String fingerPrint; + public String hexKeyId; + public int bitStrength; + public String algorithm; + public boolean secretKey; + AlgorithmNames algorithmNames; + + private boolean selected; + + /** + * Constructor for later querying from keyserver + */ + public ImportKeysListEntry() { + secretKey = 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 + * + * @param pgpKey + */ + @SuppressWarnings("unchecked") + public ImportKeysListEntry(PGPKeyRing pgpKeyRing) { + // selected is default + this.selected = true; + + if (pgpKeyRing instanceof PGPSecretKeyRing) { + secretKey = true; + } else { + secretKey = false; + } + + userIds = new ArrayList<String>(); + for (String userId : new IterableIterator<String>(pgpKeyRing.getPublicKey().getUserIDs())) { + userIds.add(userId); + } + this.keyId = pgpKeyRing.getPublicKey().getKeyID(); + + this.revoked = pgpKeyRing.getPublicKey().isRevoked(); + this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() + .getFingerprint()); + this.hexKeyId = PgpKeyHelper.convertKeyIdToHex(keyId); + 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"; + } + } +}
\ 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 new file mode 100644 index 000000000..00ad8c957 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2012-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.io.BufferedInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.openpgp.PGPKeyRing; +import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPUtil; +import org.sufficientlysecure.keychain.Constants; +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; + +public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> { + Context mContext; + + InputData mInputData; + + ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>(); + + public ImportKeysListLoader(Context context, InputData inputData) { + super(context); + this.mContext = context; + this.mInputData = inputData; + } + + @Override + public List<ImportKeysListEntry> loadInBackground() { + if (mInputData == null) { + Log.e(Constants.TAG, "Input data is null!"); + return data; + } + + generateListOfKeyrings(mInputData); + + return data; + } + + @Override + protected void onReset() { + super.onReset(); + + // Ensure the loader is stopped + onStopLoading(); + } + + @Override + protected void onStartLoading() { + forceLoad(); + } + + @Override + protected void onStopLoading() { + cancelLoad(); + } + + @Override + public void deliverResult(List<ImportKeysListEntry> data) { + super.deliverResult(data); + } + + /** + * Reads all PGPKeyRing objects from input + * + * @param keyringBytes + * @return + */ + private void generateListOfKeyrings(InputData inputData) { + PositionAwareInputStream progressIn = new PositionAwareInputStream( + inputData.getInputStream()); + + // need to have access to the bufferedInput, so we can reuse it for the possible + // PGPObject chunks after the first one, e.g. files with several consecutive ASCII + // armour blocks + BufferedInputStream bufferedInput = new BufferedInputStream(progressIn); + try { + + // read all available blocks... (asc files can contain many blocks with BEGIN END) + while (bufferedInput.available() > 0) { + InputStream in = PGPUtil.getDecoderStream(bufferedInput); + PGPObjectFactory objectFactory = new PGPObjectFactory(in); + + // go through all objects in this block + Object obj; + while ((obj = objectFactory.nextObject()) != null) { + Log.d(Constants.TAG, "Found class: " + obj.getClass()); + + if (obj instanceof PGPKeyRing) { + PGPKeyRing newKeyring = (PGPKeyRing) obj; + addToData(newKeyring); + } else { + Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); + } + } + } + } catch (Exception e) { + Log.e(Constants.TAG, "Exception on parsing key file!", e); + } + } + + private void addToData(PGPKeyRing keyring) { + ImportKeysListEntry item = new ImportKeysListEntry(keyring); + data.add(item); + } + +} 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 new file mode 100644 index 000000000..42afa2e95 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -0,0 +1,221 @@ +/* + * 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.UserIds; +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.TextView; + +/** + * Implements StickyListHeadersAdapter from library + */ +public class KeyListPublicAdapter extends CursorAdapter implements StickyListHeadersAdapter { + private LayoutInflater mInflater; + private int mSectionColumnIndex; + private int mIndexUserId; + + @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(UserIds.USER_ID); + } + } + + /** + * Bind cursor data to the item list view + * + * 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); + mainUserId.setText(R.string.unknown_user_id); + TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); + mainUserIdRest.setText(""); + + String userId = cursor.getString(mIndexUserId); + if (userId != null) { + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); + + if (userIdSplit[0] != null && userIdSplit[0].length() > 0) { + mainUserId.setText(userIdSplit[0]); + } + + if (userIdSplit[1] != null && userIdSplit[1].length() > 0) { + mainUserIdRest.setText(userIdSplit[1]); + } + } + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.key_list_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. + * + * 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.unknown_user_id); + 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 private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, + // Boolean>();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) { + // 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 new file mode 100644 index 000000000..0043203bf --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListSecretAdapter.java @@ -0,0 +1,139 @@ +/* + * 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); + mainUserId.setText(R.string.unknown_user_id); + TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); + mainUserIdRest.setText(""); + + String userId = cursor.getString(mIndexUserId); + if (userId != null) { + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); + + if (userIdSplit[0] != null && userIdSplit[0].length() > 0) { + mainUserId.setText(userIdSplit[0]); + } + + if (userIdSplit[1] != null && userIdSplit[1].length() > 0) { + mainUserIdRest.setText(userIdSplit[1]); + } + } + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.key_list_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 new file mode 100644 index 000000000..78f7b1f7e --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java @@ -0,0 +1,101 @@ +/* + * 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.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; + +public class KeyValueSpinnerAdapter extends ArrayAdapter<String> { + private final HashMap<Integer, String> mData; + private final int[] mKeys; + private final String[] mValues; + + static <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues( + Map<K, V> map) { + SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>( + new Comparator<Map.Entry<K, V>>() { + @Override + public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) { + return e1.getValue().compareTo(e2.getValue()); + } + }); + sortedEntries.addAll(map.entrySet()); + return sortedEntries; + } + + public KeyValueSpinnerAdapter(Context context, HashMap<Integer, String> objects) { + // To make the drop down a simple text box + super(context, android.R.layout.simple_spinner_item); + mData = objects; + + // To make the drop down view a radio button list + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + SortedSet<Map.Entry<Integer, String>> sorted = entriesSortedByValues(objects); + + // Assign hash keys with a position so that we can present and retrieve them + int i = 0; + mKeys = new int[mData.size()]; + mValues = new String[mData.size()]; + for (Map.Entry<Integer, String> entry : sorted) { + mKeys[i] = entry.getKey(); + mValues[i] = entry.getValue(); + i++; + } + } + + public int getCount() { + return mData.size(); + } + + /** + * Returns the value + */ + @Override + public String getItem(int position) { + // return the value based on the position. This is displayed in the list. + return mValues[position]; + } + + /** + * Returns item key + */ + public long getItemId(int position) { + // Return an id to represent the item. + + return mKeys[position]; + } + + /** + * Find position from key + */ + public int getPosition(long itemId) { + for (int i = 0; i < mKeys.length; i++) { + if ((int) itemId == mKeys[i]) { + return i; + } + } + 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 new file mode 100644 index 000000000..f4a5e1a5d --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -0,0 +1,167 @@ +/* + * 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 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; + +public class SelectKeyCursorAdapter extends CursorAdapter { + + protected int mKeyType; + + private LayoutInflater mInflater; + private ListView mListView; + + private int mIndexUserId; + private int mIndexMasterKeyId; + private int mIndexProjectionValid; + private int mIndexProjectionAvailable; + + public final static String PROJECTION_ROW_AVAILABLE = "available"; + public final static String PROJECTION_ROW_VALID = "valid"; + + public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView, + int keyType) { + super(context, c, flags); + + mInflater = LayoutInflater.from(context); + mListView = listView; + mKeyType = keyType; + + 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); + mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID); + mIndexProjectionValid = cursor.getColumnIndexOrThrow(PROJECTION_ROW_VALID); + mIndexProjectionAvailable = cursor.getColumnIndexOrThrow(PROJECTION_ROW_AVAILABLE); + } + } + + public String getUserId(int position) { + mCursor.moveToPosition(position); + return mCursor.getString(mIndexUserId); + } + + public long getMasterKeyId(int position) { + mCursor.moveToPosition(position); + return mCursor.getLong(mIndexMasterKeyId); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + boolean valid = cursor.getInt(mIndexProjectionValid) > 0; + + TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); + mainUserId.setText(R.string.unknown_user_id); + TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); + mainUserIdRest.setText(""); + TextView keyId = (TextView) view.findViewById(R.id.keyId); + keyId.setText(R.string.no_key); + TextView status = (TextView) view.findViewById(R.id.status); + status.setText(R.string.unknown_status); + + String userId = cursor.getString(mIndexUserId); + if (userId != null) { + String[] userIdSplit = PgpKeyHelper.splitUserId(userId); + + if (userIdSplit[0] != null && userIdSplit[0].length() > 0) { + mainUserId.setText(userIdSplit[0]); + } + + if (userIdSplit[1] != null && userIdSplit[1].length() > 0) { + mainUserIdRest.setText(userIdSplit[1]); + } + } + + long masterKeyId = cursor.getLong(mIndexMasterKeyId); + keyId.setText(PgpKeyHelper.convertKeyIdToHex(masterKeyId)); + + if (valid) { + if (mKeyType == Id.type.public_key) { + status.setText(R.string.can_encrypt); + } else { + status.setText(R.string.can_sign); + } + } else { + if (cursor.getInt(mIndexProjectionAvailable) > 0) { + // has some CAN_ENCRYPT keys, but col(ROW_VALID) = 0, so must be revoked or + // expired + status.setText(R.string.expired); + } else { + status.setText(R.string.no_key); + } + } + + CheckBox selected = (CheckBox) view.findViewById(R.id.selected); + if (mKeyType == Id.type.public_key) { + selected.setVisibility(View.VISIBLE); + + if (!valid) { + mListView.setItemChecked(cursor.getPosition(), false); + } + + selected.setChecked(mListView.isItemChecked(cursor.getPosition())); + selected.setEnabled(valid); + } else { + selected.setVisibility(View.GONE); + } + + status.setText(status.getText() + " "); + + view.setEnabled(valid); + mainUserId.setEnabled(valid); + mainUserIdRest.setEnabled(valid); + keyId.setEnabled(valid); + status.setEnabled(valid); + } + + @Override + 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/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java new file mode 100644 index 000000000..d5162c403 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java @@ -0,0 +1,123 @@ +/* + * 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 org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; + +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.ImageView; +import android.widget.TextView; + +public class ViewKeyKeysAdapter extends CursorAdapter { + private LayoutInflater mInflater; + + private int mIndexKeyId; + private int mIndexAlgorithm; + private int mIndexKeySize; + private int mIndexIsMasterKey; + private int mIndexCanCertify; + private int mIndexCanEncrypt; + private int mIndexCanSign; + + public ViewKeyKeysAdapter(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) { + mIndexKeyId = cursor.getColumnIndexOrThrow(Keys.KEY_ID); + mIndexAlgorithm = cursor.getColumnIndexOrThrow(Keys.ALGORITHM); + mIndexKeySize = cursor.getColumnIndexOrThrow(Keys.KEY_SIZE); + mIndexIsMasterKey = cursor.getColumnIndexOrThrow(Keys.IS_MASTER_KEY); + mIndexCanCertify = cursor.getColumnIndexOrThrow(Keys.CAN_CERTIFY); + mIndexCanEncrypt = cursor.getColumnIndexOrThrow(Keys.CAN_ENCRYPT); + mIndexCanSign = cursor.getColumnIndexOrThrow(Keys.CAN_SIGN); + } + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + String keyIdStr = "0x" + PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); + String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm), + cursor.getInt(mIndexKeySize)); + + TextView keyId = (TextView) view.findViewById(R.id.keyId); + keyId.setText(keyIdStr); + + TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails); + keyDetails.setText("(" + algorithmStr + ")"); + + ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey); + if (cursor.getInt(mIndexIsMasterKey) != 1) { + masterKeyIcon.setVisibility(View.INVISIBLE); + } else { + masterKeyIcon.setVisibility(View.VISIBLE); + } + + ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey); + if (cursor.getInt(mIndexCanCertify) != 1) { + certifyIcon.setVisibility(View.GONE); + } else { + certifyIcon.setVisibility(View.VISIBLE); + } + + ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); + if (cursor.getInt(mIndexCanEncrypt) != 1) { + encryptIcon.setVisibility(View.GONE); + } else { + encryptIcon.setVisibility(View.VISIBLE); + } + + ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); + if (cursor.getInt(mIndexCanSign) != 1) { + signIcon.setVisibility(View.GONE); + } else { + signIcon.setVisibility(View.VISIBLE); + } + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.view_key_keys_item, null); + } + +} 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 new file mode 100644 index 000000000..cf8699417 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java @@ -0,0 +1,76 @@ +/* + * 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 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.TextView; + +public class ViewKeyUserIdsAdapter extends CursorAdapter { + private LayoutInflater mInflater; + + private int mIndexUserId; + + public ViewKeyUserIdsAdapter(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) { + String userIdStr = cursor.getString(mIndexUserId); + + TextView userId = (TextView) view.findViewById(R.id.userId); + userId.setText(userIdStr); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.view_key_userids_item, null); + } + +} |