mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-17 14:25:08 -05:00
Merge branch 'development' into v/crypto-input-parcel
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
This commit is contained in:
commit
91494dd3a3
@ -28,10 +28,14 @@ import com.tokenautocomplete.TokenCompleteTextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
|
||||
import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
|
||||
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@ -91,7 +95,7 @@ public class EncryptModeAsymmetricFragment extends Fragment {
|
||||
try {
|
||||
mEncryptInterface = (IAsymmetric) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString() + " must implement IAsymmetric");
|
||||
throw new ClassCastException(activity + " must implement IAsymmetric");
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,14 +132,14 @@ public class EncryptModeAsymmetricFragment extends Fragment {
|
||||
mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() {
|
||||
@Override
|
||||
public void onTokenAdded(Object token) {
|
||||
if (token instanceof EncryptKeyCompletionView.EncryptionKey) {
|
||||
if (token instanceof KeyItem) {
|
||||
updateEncryptionKeys();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTokenRemoved(Object token) {
|
||||
if (token instanceof EncryptKeyCompletionView.EncryptionKey) {
|
||||
if (token instanceof KeyItem) {
|
||||
updateEncryptionKeys();
|
||||
}
|
||||
}
|
||||
@ -162,10 +166,10 @@ public class EncryptModeAsymmetricFragment extends Fragment {
|
||||
if (encryptionKeyIds != null) {
|
||||
for (long preselectedId : encryptionKeyIds) {
|
||||
try {
|
||||
CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing(
|
||||
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(preselectedId));
|
||||
mEncryptKeyView.addObject(mEncryptKeyView.new EncryptionKey(ring));
|
||||
} catch (PgpKeyNotFoundException e) {
|
||||
CanonicalizedPublicKeyRing ring =
|
||||
mProviderHelper.getCanonicalizedPublicKeyRing(preselectedId);
|
||||
mEncryptKeyView.addObject(new KeyItem(ring));
|
||||
} catch (NotFoundException e) {
|
||||
Log.e(Constants.TAG, "key not found!", e);
|
||||
}
|
||||
}
|
||||
@ -173,6 +177,7 @@ public class EncryptModeAsymmetricFragment extends Fragment {
|
||||
mEncryptKeyView.requestFocus();
|
||||
updateEncryptionKeys();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updateEncryptionKeys() {
|
||||
@ -180,9 +185,9 @@ public class EncryptModeAsymmetricFragment extends Fragment {
|
||||
List<Long> keyIds = new ArrayList<>();
|
||||
List<String> userIds = new ArrayList<>();
|
||||
for (Object object : objects) {
|
||||
if (object instanceof EncryptKeyCompletionView.EncryptionKey) {
|
||||
keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId());
|
||||
userIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getUserId());
|
||||
if (object instanceof KeyItem) {
|
||||
keyIds.add(((KeyItem) object).mKeyId);
|
||||
userIds.add(((KeyItem) object).mUserIdFull);
|
||||
}
|
||||
}
|
||||
long[] keyIdsArr = new long[keyIds.size()];
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
* Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2014-2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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
|
||||
@ -26,7 +26,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@ -37,7 +36,6 @@ import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
@ -49,8 +47,6 @@ import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView.MultiChoiceModeListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
@ -64,7 +60,6 @@ import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||
@ -75,9 +70,8 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
||||
import org.sufficientlysecure.keychain.ui.util.Highlighter;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||
import org.sufficientlysecure.keychain.util.FabContainer;
|
||||
@ -292,26 +286,6 @@ public class KeyListFragment extends LoaderFragment
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
|
||||
// These are the rows that we will retrieve.
|
||||
static final String[] PROJECTION = new String[]{
|
||||
KeyRings._ID,
|
||||
KeyRings.MASTER_KEY_ID,
|
||||
KeyRings.USER_ID,
|
||||
KeyRings.IS_REVOKED,
|
||||
KeyRings.IS_EXPIRED,
|
||||
KeyRings.VERIFIED,
|
||||
KeyRings.HAS_ANY_SECRET,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
};
|
||||
|
||||
static final int INDEX_MASTER_KEY_ID = 1;
|
||||
static final int INDEX_USER_ID = 2;
|
||||
static final int INDEX_IS_REVOKED = 3;
|
||||
static final int INDEX_IS_EXPIRED = 4;
|
||||
static final int INDEX_VERIFIED = 5;
|
||||
static final int INDEX_HAS_ANY_SECRET = 6;
|
||||
static final int INDEX_HAS_DUPLICATE_USER_ID = 7;
|
||||
|
||||
static final String ORDER =
|
||||
KeyRings.HAS_ANY_SECRET + " DESC, UPPER(" + KeyRings.USER_ID + ") ASC";
|
||||
|
||||
@ -339,7 +313,8 @@ public class KeyListFragment extends LoaderFragment
|
||||
|
||||
// Now create and return a CursorLoader that will take care of
|
||||
// creating a Cursor for the data being displayed.
|
||||
return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, ORDER);
|
||||
return new CursorLoader(getActivity(), baseUri,
|
||||
KeyListAdapter.PROJECTION, where, whereArgs, ORDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -787,148 +762,54 @@ public class KeyListFragment extends LoaderFragment
|
||||
anim.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements StickyListHeadersAdapter from library
|
||||
*/
|
||||
private class KeyListAdapter extends CursorAdapter implements StickyListHeadersAdapter {
|
||||
private String mQuery;
|
||||
private LayoutInflater mInflater;
|
||||
public class KeyListAdapter extends KeyAdapter implements StickyListHeadersAdapter {
|
||||
|
||||
private HashMap<Integer, Boolean> mSelection = new HashMap<>();
|
||||
|
||||
public KeyListAdapter(Context context, Cursor c, int flags) {
|
||||
super(context, c, flags);
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
public void setSearchQuery(String query) {
|
||||
mQuery = query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor swapCursor(Cursor newCursor) {
|
||||
return super.swapCursor(newCursor);
|
||||
}
|
||||
|
||||
private class ItemViewHolder {
|
||||
Long mMasterKeyId;
|
||||
TextView mMainUserId;
|
||||
TextView mMainUserIdRest;
|
||||
ImageView mStatus;
|
||||
View mSlinger;
|
||||
ImageButton mSlingerButton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
View view = mInflater.inflate(R.layout.key_list_item, parent, false);
|
||||
final ItemViewHolder holder = new ItemViewHolder();
|
||||
holder.mMainUserId = (TextView) view.findViewById(R.id.key_list_item_name);
|
||||
holder.mMainUserIdRest = (TextView) view.findViewById(R.id.key_list_item_email);
|
||||
holder.mStatus = (ImageView) view.findViewById(R.id.key_list_item_status_icon);
|
||||
holder.mSlinger = view.findViewById(R.id.key_list_item_slinger_view);
|
||||
holder.mSlingerButton = (ImageButton) view.findViewById(R.id.key_list_item_slinger_button);
|
||||
holder.mSlingerButton.setColorFilter(context.getResources().getColor(R.color.tertiary_text_light),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
view.setTag(holder);
|
||||
view.findViewById(R.id.key_list_item_slinger_button).setOnClickListener(new OnClickListener() {
|
||||
View view = super.newView(context, cursor, parent);
|
||||
|
||||
final KeyItemViewHolder holder = (KeyItemViewHolder) view.getTag();
|
||||
|
||||
holder.mSlinger.setVisibility(View.VISIBLE);
|
||||
holder.mSlingerButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (holder.mMasterKeyId != null) {
|
||||
Intent safeSlingerIntent = new Intent(getActivity(), SafeSlingerActivity.class);
|
||||
Intent safeSlingerIntent = new Intent(mContext, SafeSlingerActivity.class);
|
||||
safeSlingerIntent.putExtra(SafeSlingerActivity.EXTRA_MASTER_KEY_ID, holder.mMasterKeyId);
|
||||
startActivityForResult(safeSlingerIntent, REQUEST_ACTION);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind cursor data to the item list view
|
||||
*/
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
Highlighter highlighter = new Highlighter(context, mQuery);
|
||||
ItemViewHolder h = (ItemViewHolder) view.getTag();
|
||||
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);
|
||||
|
||||
{ // set name and stuff, common to both key types
|
||||
String userId = cursor.getString(INDEX_USER_ID);
|
||||
KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId);
|
||||
if (userIdSplit.name != null) {
|
||||
h.mMainUserId.setText(highlighter.highlight(userIdSplit.name));
|
||||
} else {
|
||||
h.mMainUserId.setText(R.string.user_id_no_name);
|
||||
}
|
||||
if (userIdSplit.email != null) {
|
||||
h.mMainUserIdRest.setText(highlighter.highlight(userIdSplit.email));
|
||||
h.mMainUserIdRest.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
h.mMainUserIdRest.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
{ // set edit button and status, specific by key type
|
||||
|
||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
boolean isSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
||||
boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
|
||||
boolean hasDuplicate = cursor.getInt(INDEX_HAS_DUPLICATE_USER_ID) == 1;
|
||||
|
||||
h.mMasterKeyId = masterKeyId;
|
||||
|
||||
// Note: order is important!
|
||||
if (isRevoked) {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, State.REVOKED, R.color.bg_gray);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
h.mSlinger.setVisibility(View.GONE);
|
||||
h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
} else if (isExpired) {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, State.EXPIRED, R.color.bg_gray);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
h.mSlinger.setVisibility(View.GONE);
|
||||
h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
} else if (isSecret) {
|
||||
h.mStatus.setVisibility(View.GONE);
|
||||
h.mSlinger.setVisibility(View.VISIBLE);
|
||||
h.mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
|
||||
h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
|
||||
} else {
|
||||
// this is a public key - show if it's verified
|
||||
if (isVerified) {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, State.VERIFIED);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, State.UNVERIFIED);
|
||||
h.mStatus.setVisibility(View.VISIBLE);
|
||||
}
|
||||
h.mSlinger.setVisibility(View.GONE);
|
||||
h.mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
|
||||
h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
|
||||
}
|
||||
if (mSelection.get(position) != null) {
|
||||
// selected position color
|
||||
v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
|
||||
} else {
|
||||
// default color
|
||||
v.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean isSecretAvailable(int id) {
|
||||
if (!mCursor.moveToPosition(id)) {
|
||||
throw new IllegalStateException("couldn't move cursor to position " + id);
|
||||
}
|
||||
|
||||
return mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||
}
|
||||
|
||||
public long getMasterKeyId(int id) {
|
||||
if (!mCursor.moveToPosition(id)) {
|
||||
throw new IllegalStateException("couldn't move cursor to position " + id);
|
||||
}
|
||||
|
||||
return mCursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
private class HeaderViewHolder {
|
||||
TextView mText;
|
||||
TextView mCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -961,10 +842,10 @@ public class KeyListFragment extends LoaderFragment
|
||||
throw new IllegalStateException("couldn't move cursor to position " + position);
|
||||
}
|
||||
|
||||
if (mCursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
|
||||
if (mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0) {
|
||||
{ // set contact count
|
||||
int num = mCursor.getCount();
|
||||
String contactsTotal = getResources().getQuantityString(R.plurals.n_keys, num, num);
|
||||
String contactsTotal = mContext.getResources().getQuantityString(R.plurals.n_keys, num, num);
|
||||
holder.mCount.setText(contactsTotal);
|
||||
holder.mCount.setVisibility(View.VISIBLE);
|
||||
}
|
||||
@ -974,7 +855,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
}
|
||||
|
||||
// set header text as first char in user id
|
||||
String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
|
||||
String userId = mCursor.getString(INDEX_USER_ID);
|
||||
String headerText = convertView.getResources().getString(R.string.user_id_no_name);
|
||||
if (userId != null && userId.length() > 0) {
|
||||
headerText = "" + userId.charAt(0);
|
||||
@ -1000,11 +881,11 @@ public class KeyListFragment extends LoaderFragment
|
||||
}
|
||||
|
||||
// early breakout: all secret keys are assigned id 0
|
||||
if (mCursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
|
||||
if (mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0) {
|
||||
return 1L;
|
||||
}
|
||||
// otherwise, return the first character of the name as ID
|
||||
String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
|
||||
String userId = mCursor.getString(INDEX_USER_ID);
|
||||
if (userId != null && userId.length() > 0) {
|
||||
return Character.toUpperCase(userId.charAt(0));
|
||||
} else {
|
||||
@ -1012,11 +893,6 @@ public class KeyListFragment extends LoaderFragment
|
||||
}
|
||||
}
|
||||
|
||||
private class HeaderViewHolder {
|
||||
TextView mText;
|
||||
TextView mCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* -------------------------- MULTI-SELECTION METHODS --------------
|
||||
*/
|
||||
@ -1027,7 +903,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
|
||||
public boolean isAnySecretSelected() {
|
||||
for (int pos : mSelection.keySet()) {
|
||||
if (mAdapter.isSecretAvailable(pos))
|
||||
if (isSecretAvailable(pos))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -1038,7 +914,7 @@ public class KeyListFragment extends LoaderFragment
|
||||
int i = 0;
|
||||
// get master key ids
|
||||
for (int pos : mSelection.keySet()) {
|
||||
ids[i++] = mAdapter.getMasterKeyId(pos);
|
||||
ids[i++] = getMasterKeyId(pos);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
@ -1053,26 +929,6 @@ public class KeyListFragment extends LoaderFragment
|
||||
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
|
||||
*/
|
||||
if (mSelection.get(position) != null) {
|
||||
// selected position color
|
||||
v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
|
||||
} else {
|
||||
// default color
|
||||
v.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.PorterDuff;
|
||||
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.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.ui.util.Highlighter;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||
|
||||
public class KeyAdapter extends CursorAdapter {
|
||||
|
||||
protected String mQuery;
|
||||
protected LayoutInflater mInflater;
|
||||
|
||||
// These are the rows that we will retrieve.
|
||||
public static final String[] PROJECTION = new String[]{
|
||||
KeyRings._ID,
|
||||
KeyRings.MASTER_KEY_ID,
|
||||
KeyRings.USER_ID,
|
||||
KeyRings.IS_REVOKED,
|
||||
KeyRings.IS_EXPIRED,
|
||||
KeyRings.VERIFIED,
|
||||
KeyRings.HAS_ANY_SECRET,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeyRings.HAS_ENCRYPT,
|
||||
KeyRings.FINGERPRINT,
|
||||
KeyRings.CREATION,
|
||||
};
|
||||
|
||||
public static final int INDEX_MASTER_KEY_ID = 1;
|
||||
public static final int INDEX_USER_ID = 2;
|
||||
public static final int INDEX_IS_REVOKED = 3;
|
||||
public static final int INDEX_IS_EXPIRED = 4;
|
||||
public static final int INDEX_VERIFIED = 5;
|
||||
public static final int INDEX_HAS_ANY_SECRET = 6;
|
||||
public static final int INDEX_HAS_DUPLICATE_USER_ID = 7;
|
||||
public static final int INDEX_HAS_ENCRYPT = 8;
|
||||
public static final int INDEX_FINGERPRINT = 9;
|
||||
public static final int INDEX_CREATION = 10;
|
||||
|
||||
public KeyAdapter(Context context, Cursor c, int flags) {
|
||||
super(context, c, flags);
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
public void setSearchQuery(String query) {
|
||||
mQuery = query;
|
||||
}
|
||||
|
||||
public static class KeyItemViewHolder {
|
||||
public Long mMasterKeyId;
|
||||
public TextView mMainUserId;
|
||||
public TextView mMainUserIdRest;
|
||||
public ImageView mStatus;
|
||||
public View mSlinger;
|
||||
public ImageButton mSlingerButton;
|
||||
|
||||
public KeyItemViewHolder(View view) {
|
||||
mMainUserId = (TextView) view.findViewById(R.id.key_list_item_name);
|
||||
mMainUserIdRest = (TextView) view.findViewById(R.id.key_list_item_email);
|
||||
mStatus = (ImageView) view.findViewById(R.id.key_list_item_status_icon);
|
||||
mSlinger = view.findViewById(R.id.key_list_item_slinger_view);
|
||||
mSlingerButton = (ImageButton) view.findViewById(R.id.key_list_item_slinger_button);
|
||||
}
|
||||
|
||||
public void setData(Context context, Cursor cursor, Highlighter highlighter) {
|
||||
|
||||
{ // set name and stuff, common to both key types
|
||||
String userId = cursor.getString(INDEX_USER_ID);
|
||||
KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId);
|
||||
if (userIdSplit.name != null) {
|
||||
mMainUserId.setText(highlighter.highlight(userIdSplit.name));
|
||||
} else {
|
||||
mMainUserId.setText(R.string.user_id_no_name);
|
||||
}
|
||||
if (userIdSplit.email != null) {
|
||||
mMainUserIdRest.setText(highlighter.highlight(userIdSplit.email));
|
||||
mMainUserIdRest.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mMainUserIdRest.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
{ // set edit button and status, specific by key type
|
||||
|
||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
boolean isSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
||||
boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
|
||||
boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
|
||||
// boolean hasDuplicate = cursor.getInt(INDEX_HAS_DUPLICATE_USER_ID) == 1;
|
||||
|
||||
mMasterKeyId = masterKeyId;
|
||||
|
||||
// Note: order is important!
|
||||
if (isRevoked) {
|
||||
KeyFormattingUtils
|
||||
.setStatusImage(context, mStatus, null, State.REVOKED, R.color.bg_gray);
|
||||
mStatus.setVisibility(View.VISIBLE);
|
||||
mSlinger.setVisibility(View.GONE);
|
||||
mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
} else if (isExpired) {
|
||||
KeyFormattingUtils.setStatusImage(context, mStatus, null, State.EXPIRED, R.color.bg_gray);
|
||||
mStatus.setVisibility(View.VISIBLE);
|
||||
mSlinger.setVisibility(View.GONE);
|
||||
mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
|
||||
} else if (isSecret) {
|
||||
mStatus.setVisibility(View.GONE);
|
||||
if (mSlingerButton.hasOnClickListeners()) {
|
||||
mSlinger.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
|
||||
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
|
||||
} else {
|
||||
// this is a public key - show if it's verified
|
||||
if (isVerified) {
|
||||
KeyFormattingUtils.setStatusImage(context, mStatus, State.VERIFIED);
|
||||
mStatus.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
KeyFormattingUtils.setStatusImage(context, mStatus, State.UNVERIFIED);
|
||||
mStatus.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mSlinger.setVisibility(View.GONE);
|
||||
mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
|
||||
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
View view = mInflater.inflate(R.layout.key_list_item, parent, false);
|
||||
KeyItemViewHolder holder = new KeyItemViewHolder(view);
|
||||
view.setTag(holder);
|
||||
holder.mSlingerButton.setColorFilter(context.getResources().getColor(R.color.tertiary_text_light),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
Highlighter highlighter = new Highlighter(context, mQuery);
|
||||
KeyItemViewHolder h = (KeyItemViewHolder) view.getTag();
|
||||
h.setData(context, cursor, highlighter);
|
||||
}
|
||||
|
||||
public boolean isSecretAvailable(int id) {
|
||||
if (!mCursor.moveToPosition(id)) {
|
||||
throw new IllegalStateException("couldn't move cursor to position " + id);
|
||||
}
|
||||
|
||||
return mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||
}
|
||||
|
||||
public long getMasterKeyId(int id) {
|
||||
if (!mCursor.moveToPosition(id)) {
|
||||
throw new IllegalStateException("couldn't move cursor to position " + id);
|
||||
}
|
||||
|
||||
return mCursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyItem getItem(int position) {
|
||||
Cursor c = getCursor();
|
||||
if (c.isClosed() || !c.moveToPosition(position)) {
|
||||
return null;
|
||||
}
|
||||
return new KeyItem(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
// prevent a crash on rapid cursor changes
|
||||
if (getCursor().isClosed()) {
|
||||
return 0L;
|
||||
}
|
||||
return super.getItemId(position);
|
||||
}
|
||||
|
||||
public static class KeyItem {
|
||||
|
||||
public final String mUserIdFull;
|
||||
public final KeyRing.UserId mUserId;
|
||||
public final long mKeyId;
|
||||
public final boolean mHasDuplicate;
|
||||
public final Date mCreation;
|
||||
public final String mFingerprint;
|
||||
|
||||
private KeyItem(Cursor cursor) {
|
||||
String userId = cursor.getString(INDEX_USER_ID);
|
||||
mUserId = KeyRing.splitUserId(userId);
|
||||
mUserIdFull = userId;
|
||||
mKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
mHasDuplicate = cursor.getLong(INDEX_HAS_DUPLICATE_USER_ID) > 0;
|
||||
mCreation = new Date(cursor.getLong(INDEX_CREATION) * 1000);
|
||||
mFingerprint = KeyFormattingUtils.convertFingerprintToHex(
|
||||
cursor.getBlob(INDEX_FINGERPRINT));
|
||||
}
|
||||
|
||||
public KeyItem(CanonicalizedPublicKeyRing ring) {
|
||||
CanonicalizedPublicKey key = ring.getPublicKey();
|
||||
String userId = key.getPrimaryUserIdWithFallback();
|
||||
mUserId = KeyRing.splitUserId(userId);
|
||||
mUserIdFull = userId;
|
||||
mKeyId = ring.getMasterKeyId();
|
||||
mHasDuplicate = false;
|
||||
mCreation = key.getCreationTime();
|
||||
mFingerprint = KeyFormattingUtils.convertFingerprintToHex(
|
||||
ring.getFingerprint());
|
||||
}
|
||||
|
||||
public String getReadableName() {
|
||||
if (mUserId.name != null) {
|
||||
return mUserId.name;
|
||||
} else {
|
||||
return mUserId.email;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasDuplicate() {
|
||||
return mHasDuplicate;
|
||||
}
|
||||
|
||||
public String getCreationDate(Context context) {
|
||||
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
creationCal.setTime(mCreation);
|
||||
// convert from UTC to time zone of device
|
||||
creationCal.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
return context.getString(R.string.label_creation) + ": "
|
||||
+ DateFormat.getDateFormat(context).format(creationCal.getTime());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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
|
||||
@ -17,49 +18,42 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.widget;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tokenautocomplete.FilteredArrayAdapter;
|
||||
import com.tokenautocomplete.TokenCompleteTextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
public class EncryptKeyCompletionView extends TokenCompleteTextView
|
||||
implements LoaderCallbacks<Cursor> {
|
||||
|
||||
public static final String ARG_QUERY = "query";
|
||||
|
||||
private KeyAdapter mAdapter;
|
||||
private LoaderManager mLoaderManager;
|
||||
private String mPrefix;
|
||||
|
||||
public EncryptKeyCompletionView(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
@ -76,33 +70,31 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
swapCursor(null);
|
||||
setPrefix(getContext().getString(R.string.label_to) + " ");
|
||||
|
||||
allowDuplicates(false);
|
||||
mAdapter = new KeyAdapter(getContext(), null, 0);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrefix(String p) {
|
||||
// this one is private in the superclass, but we need it here
|
||||
mPrefix = p;
|
||||
super.setPrefix(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View getViewForObject(Object object) {
|
||||
if (object instanceof EncryptionKey) {
|
||||
LayoutInflater l = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
|
||||
if (object instanceof KeyItem) {
|
||||
LayoutInflater l = LayoutInflater.from(getContext());
|
||||
View view = l.inflate(R.layout.recipient_box_entry, null);
|
||||
((TextView) view.findViewById(android.R.id.text1)).setText(((EncryptionKey) object).getPrimary());
|
||||
setImageByKey((ImageView) view.findViewById(android.R.id.icon), (EncryptionKey) object);
|
||||
((TextView) view.findViewById(android.R.id.text1)).setText(((KeyItem) object).getReadableName());
|
||||
return view;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setImageByKey(ImageView view, EncryptionKey key) {
|
||||
Bitmap photo = ContactHelper.getCachedPhotoByMasterKeyId(getContext().getContentResolver(), key.getKeyId());
|
||||
|
||||
if (photo != null) {
|
||||
view.setImageBitmap(photo);
|
||||
} else {
|
||||
view.setImageResource(R.drawable.ic_generic_man);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object defaultObject(String completionText) {
|
||||
// TODO: We could try to automagically download the key if it's unknown but a key id
|
||||
@ -115,46 +107,54 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
mLoaderManager = ((FragmentActivity) getContext()).getSupportLoaderManager();
|
||||
|
||||
if (getContext() instanceof FragmentActivity) {
|
||||
((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(hashCode(), null, new LoaderManager.LoaderCallbacks<Cursor>() {
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
// These are the rows that we will retrieve.
|
||||
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
|
||||
|
||||
String[] projection = new String[]{
|
||||
KeyRings._ID,
|
||||
KeyRings.MASTER_KEY_ID,
|
||||
KeyRings.KEY_ID,
|
||||
KeyRings.USER_ID,
|
||||
KeyRings.FINGERPRINT,
|
||||
KeyRings.IS_EXPIRED,
|
||||
KeyRings.HAS_ENCRYPT,
|
||||
KeyRings.HAS_DUPLICATE_USER_ID,
|
||||
KeyRings.CREATION
|
||||
};
|
||||
|
||||
String where = KeyRings.HAS_ENCRYPT + " NOT NULL AND " + KeyRings.IS_EXPIRED + " = 0 AND "
|
||||
+ Tables.KEYS + "." + KeyRings.IS_REVOKED + " = 0";
|
||||
|
||||
return new CursorLoader(getContext(), baseUri, projection, where, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
swapCursor(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
swapCursor(null);
|
||||
}
|
||||
});
|
||||
mLoaderManager.initLoader(hashCode(), null, this);
|
||||
} else {
|
||||
Log.e(Constants.TAG, "EncryptKeyCompletionView must be attached to a FragmentActivity, this is " + getContext().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mLoaderManager = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
// These are the rows that we will retrieve.
|
||||
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
|
||||
String where = KeyRings.HAS_ENCRYPT + " NOT NULL AND " + KeyRings.IS_EXPIRED + " = 0 AND "
|
||||
+ Tables.KEYS + "." + KeyRings.IS_REVOKED + " = 0";
|
||||
|
||||
if (args != null && args.containsKey(ARG_QUERY)) {
|
||||
String query = args.getString(ARG_QUERY);
|
||||
mAdapter.setSearchQuery(query);
|
||||
|
||||
where += " AND " + KeyRings.USER_ID + " LIKE ?";
|
||||
|
||||
return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where,
|
||||
new String[] { "%" + query + "%" }, null);
|
||||
}
|
||||
|
||||
mAdapter.setSearchQuery(null);
|
||||
return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where, null, null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
mAdapter.swapCursor(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
mAdapter.swapCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFocusChanged(boolean hasFocus, int direction, Rect previous) {
|
||||
super.onFocusChanged(hasFocus, direction, previous);
|
||||
@ -164,147 +164,15 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
|
||||
}
|
||||
}
|
||||
|
||||
public void swapCursor(Cursor cursor) {
|
||||
if (cursor == null) {
|
||||
setAdapter(new EncryptKeyAdapter(Collections.<EncryptionKey>emptyList()));
|
||||
return;
|
||||
@Override
|
||||
protected void performFiltering(CharSequence text, int start, int end, int keyCode) {
|
||||
super.performFiltering(text, start, end, keyCode);
|
||||
if (start < mPrefix.length()) {
|
||||
start = mPrefix.length();
|
||||
}
|
||||
ArrayList<EncryptionKey> keys = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
try {
|
||||
EncryptionKey key = new EncryptionKey(cursor);
|
||||
keys.add(key);
|
||||
} catch (Exception e) {
|
||||
Log.w(Constants.TAG, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setAdapter(new EncryptKeyAdapter(keys));
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARG_QUERY, text.subSequence(start, end).toString());
|
||||
mLoaderManager.restartLoader(hashCode(), args, this);
|
||||
}
|
||||
|
||||
public class EncryptionKey {
|
||||
private String mUserIdFull;
|
||||
private KeyRing.UserId mUserId;
|
||||
private long mKeyId;
|
||||
private boolean mHasDuplicate;
|
||||
private Date mCreation;
|
||||
private String mFingerprint;
|
||||
|
||||
public EncryptionKey(String userId, long keyId, boolean hasDuplicate, Date creation, String fingerprint) {
|
||||
mUserId = KeyRing.splitUserId(userId);
|
||||
mUserIdFull = userId;
|
||||
mKeyId = keyId;
|
||||
mHasDuplicate = hasDuplicate;
|
||||
mCreation = creation;
|
||||
mFingerprint = fingerprint;
|
||||
}
|
||||
|
||||
public EncryptionKey(Cursor cursor) {
|
||||
this(cursor.getString(cursor.getColumnIndexOrThrow(KeyRings.USER_ID)),
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.KEY_ID)),
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.HAS_DUPLICATE_USER_ID)) > 0,
|
||||
new Date(cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.CREATION)) * 1000),
|
||||
KeyFormattingUtils.convertFingerprintToHex(
|
||||
cursor.getBlob(cursor.getColumnIndexOrThrow(KeyRings.FINGERPRINT))));
|
||||
}
|
||||
|
||||
public EncryptionKey(CachedPublicKeyRing ring) throws PgpKeyNotFoundException {
|
||||
this(ring.getPrimaryUserId(), ring.extractOrGetMasterKeyId(), false, null,
|
||||
KeyFormattingUtils.convertFingerprintToHex(ring.getFingerprint()));
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return mUserIdFull;
|
||||
}
|
||||
|
||||
public String getFingerprint() {
|
||||
return mFingerprint;
|
||||
}
|
||||
|
||||
public String getPrimary() {
|
||||
if (mUserId.name != null) {
|
||||
return mUserId.name;
|
||||
} else {
|
||||
return mUserId.email;
|
||||
}
|
||||
}
|
||||
|
||||
public String getSecondary() {
|
||||
if (mUserId.email != null) {
|
||||
return mUserId.email;
|
||||
} else {
|
||||
return getCreationDate();
|
||||
}
|
||||
}
|
||||
|
||||
public String getTertiary() {
|
||||
if (mUserId.name != null) {
|
||||
return getCreationDate();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public long getKeyId() {
|
||||
return mKeyId;
|
||||
}
|
||||
|
||||
public String getCreationDate() {
|
||||
if (mHasDuplicate) {
|
||||
Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
creationCal.setTime(mCreation);
|
||||
// convert from UTC to time zone of device
|
||||
creationCal.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
return getContext().getString(R.string.label_creation) + ": "
|
||||
+ DateFormat.getDateFormat(getContext()).format(creationCal.getTime());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getKeyIdHex() {
|
||||
return KeyFormattingUtils.beautifyKeyIdWithPrefix(getContext(), mKeyId);
|
||||
}
|
||||
|
||||
public String getKeyIdHexShort() {
|
||||
return KeyFormattingUtils.convertKeyIdToHexShort(mKeyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Long.toString(mKeyId);
|
||||
}
|
||||
}
|
||||
|
||||
private class EncryptKeyAdapter extends FilteredArrayAdapter<EncryptionKey> {
|
||||
|
||||
public EncryptKeyAdapter(List<EncryptionKey> objs) {
|
||||
super(EncryptKeyCompletionView.this.getContext(), 0, 0, objs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
LayoutInflater l = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
|
||||
View view;
|
||||
if (convertView != null) {
|
||||
view = convertView;
|
||||
} else {
|
||||
view = l.inflate(R.layout.recipient_selection_list_entry, null);
|
||||
}
|
||||
((TextView) view.findViewById(android.R.id.title)).setText(getItem(position).getPrimary());
|
||||
((TextView) view.findViewById(android.R.id.text1)).setText(getItem(position).getSecondary());
|
||||
((TextView) view.findViewById(android.R.id.text2)).setText(getItem(position).getTertiary());
|
||||
setImageByKey((ImageView) view.findViewById(android.R.id.icon), getItem(position));
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean keepObject(EncryptionKey obj, String mask) {
|
||||
String m = mask.toLowerCase(Locale.ENGLISH);
|
||||
return obj.getUserId().toLowerCase(Locale.ENGLISH).contains(m) ||
|
||||
obj.getKeyIdHex().contains(m) ||
|
||||
obj.getKeyIdHexShort().startsWith(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
@ -69,7 +70,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/status_signature_revoked_cutout_24dp"
|
||||
android:padding="16dp" />
|
||||
android:padding="16dp"
|
||||
tools:src="@drawable/status_signature_revoked_cutout_24dp"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -19,5 +19,7 @@
|
||||
android:layout_marginLeft="12dip"
|
||||
android:cropToPadding="true"
|
||||
android:background="#ccc"
|
||||
android:scaleType="centerCrop" />
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/ic_person_grey_24dp" />
|
||||
|
||||
</LinearLayout>
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dip"
|
||||
@ -21,7 +22,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dip"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end" />
|
||||
android:ellipsize="end"
|
||||
tools:text="Alice" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/text1"
|
||||
@ -32,7 +34,8 @@
|
||||
android:paddingLeft="16dip"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginTop="-4dip" />
|
||||
android:layout_marginTop="-4dip"
|
||||
tools:text="alice@example.com" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/text2"
|
||||
@ -43,15 +46,18 @@
|
||||
android:paddingLeft="16dip"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginTop="-4dip" />
|
||||
android:layout_marginTop="-4dip"
|
||||
tools:text="Creation 12.03.2015" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="56dip"
|
||||
android:layout_height="56dip"
|
||||
android:layout_marginLeft="12dip"
|
||||
android:cropToPadding="true"
|
||||
android:background="#ccc"
|
||||
android:scaleType="centerCrop" />
|
||||
android:id="@+id/status_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="16dp"
|
||||
tools:src="@drawable/status_signature_revoked_cutout_24dp"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
Loading…
Reference in New Issue
Block a user