From d27925ad19b6800658a69670ceaed261776ba6d3 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 30 Mar 2015 02:42:16 +0200 Subject: rewrite EncryptKeyCompletionView with generalized KeyAdapter --- .../ui/widget/EncryptKeyCompletionView.java | 278 ++++++--------------- 1 file changed, 73 insertions(+), 205 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java index ceace1d26..b2dfb2493 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014-2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser * * 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 { + + 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,196 +107,72 @@ 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() { - @Override - public Loader 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 loader, Cursor data) { - swapCursor(data); - } - - @Override - public void onLoaderReset(Loader 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 - public void onFocusChanged(boolean hasFocus, int direction, Rect previous) { - super.onFocusChanged(hasFocus, direction, previous); - if (hasFocus) { - ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)) - .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT); - } + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mLoaderManager = null; } - public void swapCursor(Cursor cursor) { - if (cursor == null) { - setAdapter(new EncryptKeyAdapter(Collections.emptyList())); - return; - } - ArrayList 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)); - } - - 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; - } - } + @Override + public Loader 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"; - public long getKeyId() { - return mKeyId; - } + if (args != null && args.containsKey(ARG_QUERY)) { + String query = args.getString(ARG_QUERY); + mAdapter.setSearchQuery(query); - 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; - } - } + where += " AND " + KeyRings.USER_ID + " LIKE ?"; - public String getKeyIdHex() { - return KeyFormattingUtils.beautifyKeyIdWithPrefix(getContext(), mKeyId); + return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where, + new String[] { "%" + query + "%" }, null); } - public String getKeyIdHexShort() { - return KeyFormattingUtils.convertKeyIdToHexShort(mKeyId); - } + mAdapter.setSearchQuery(null); + return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where, null, null); - @Override - public String toString() { - return Long.toString(mKeyId); - } } - private class EncryptKeyAdapter extends FilteredArrayAdapter { + @Override + public void onLoadFinished(Loader loader, Cursor data) { + mAdapter.swapCursor(data); + } - public EncryptKeyAdapter(List objs) { - super(EncryptKeyCompletionView.this.getContext(), 0, 0, objs); - } + @Override + public void onLoaderReset(Loader loader) { + mAdapter.swapCursor(null); + } - @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 + public void onFocusChanged(boolean hasFocus, int direction, Rect previous) { + super.onFocusChanged(hasFocus, direction, previous); + if (hasFocus) { + ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)) + .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT); } + } - @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); - } + @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(); + } + Bundle args = new Bundle(); + args.putString(ARG_QUERY, text.subSequence(start, end).toString()); + mLoaderManager.restartLoader(hashCode(), args, this); } + } -- cgit v1.2.3