diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectEncryptKeyAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectEncryptKeyAdapter.java deleted file mode 100644 index 48c75b29a..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectEncryptKeyAdapter.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2017 Schürmann & Breitmoser GbR - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote.ui.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.RecyclerView; -import android.text.format.DateUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.ui.adapter.KeyCursorAdapter; -import org.sufficientlysecure.keychain.ui.util.FormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Highlighter; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter; - -import java.util.ArrayList; -import java.util.Arrays; - -public class SelectEncryptKeyAdapter extends KeyCursorAdapter { - - private ArrayList mSelected; - - public SelectEncryptKeyAdapter(Context context, PublicKeyCursor cursor) { - super(context, cursor); - - mSelected = new ArrayList<>(); - } - - private boolean isSelected(int position) { - return mSelected.contains(position); - } - - private void select(int position) { - if (!isSelected(position)) { - mSelected.add(position); - notifyItemChanged(position); - } - } - - private void switchSelected(int position) { - int index = mSelected.indexOf(position); - if (index < 0) { - mSelected.add(position); - } else { - mSelected.remove(index); - } - - notifyItemChanged(position); - } - - public long[] getMasterKeyIds() { - long[] selected = new long[mSelected.size()]; - for (int i = 0; i < selected.length; i++) { - int position = mSelected.get(i); - if (!moveCursor(position)) { - return selected; - } - - selected[i] = getCursor().getKeyId(); - } - - return selected; - } - - public void preselectMasterKeyIds(long[] keyIds) { - if (keyIds != null) { - int count = 0; - for (int i = 0; i < getItemCount(); i++) { - if (!moveCursor(i)) { - continue; - } - - long id = getCursor().getKeyId(); - for (long keyId : keyIds) { - if (id == keyId) { - select(i); - count++; - break; - } - } - - if (count >= keyIds.length) { - return; - } - } - } - } - - @Override - public void onContentChanged() { - mSelected.clear(); - super.onContentChanged(); - } - - @Override - public void onBindViewHolder(EncryptKeyItemHolder holder, PublicKeyCursor cursor, String query) { - holder.bind(cursor, query, isSelected(holder.getAdapterPosition())); - } - - @Override - public EncryptKeyItemHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new EncryptKeyItemHolder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.select_encrypt_key_item, parent, false)); - } - - class EncryptKeyItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener { - private TextView mUserIdText; - private TextView mUserIdRestText; - private TextView mCreationText; - private ImageView mStatusIcon; - private CheckBox mChecked; - - public EncryptKeyItemHolder(View itemView) { - super(itemView); - itemView.setOnClickListener(this); - - mUserIdText = itemView.findViewById(R.id.select_key_item_name); - mUserIdRestText = itemView.findViewById(R.id.select_key_item_email); - mCreationText = itemView.findViewById(R.id.select_key_item_creation); - mStatusIcon = itemView.findViewById(R.id.select_key_item_status_icon); - mChecked = itemView.findViewById(R.id.selected); - } - - public void bind(PublicKeyCursor cursor, String query, boolean selected) { - Highlighter highlighter = new Highlighter(itemView.getContext(), query); - Context context = itemView.getContext(); - - { // set name and stuff, common to both key types - String name = cursor.getName(); - String email = cursor.getEmail(); - if (name != null) { - mUserIdText.setText(highlighter.highlight(name)); - } else { - mUserIdText.setText(R.string.user_id_no_name); - } - if (email != null) { - mUserIdRestText.setText(highlighter.highlight(email)); - mUserIdRestText.setVisibility(View.VISIBLE); - } else { - mUserIdRestText.setVisibility(View.GONE); - } - } - - boolean enabled; - { // set edit button and status, specific by key type. Note: order is important! - int textColor; - if (cursor.isRevoked()) { - KeyFormattingUtils.setStatusImage( - context, - mStatusIcon, - null, - KeyFormattingUtils.State.REVOKED, - R.color.key_flag_gray - ); - - mStatusIcon.setVisibility(View.VISIBLE); - - enabled = false; - textColor = ContextCompat.getColor(context, R.color.key_flag_gray); - } else if (cursor.isExpired()) { - KeyFormattingUtils.setStatusImage( - context, - mStatusIcon, - null, - KeyFormattingUtils.State.EXPIRED, - R.color.key_flag_gray - ); - - mStatusIcon.setVisibility(View.VISIBLE); - - enabled = false; - textColor = ContextCompat.getColor(context, R.color.key_flag_gray); - } else if (!cursor.hasEncrypt()) { - KeyFormattingUtils.setStatusImage( - context, - mStatusIcon, - KeyFormattingUtils.State.UNAVAILABLE - ); - - mStatusIcon.setVisibility(View.VISIBLE); - - enabled = false; - textColor = ContextCompat.getColor(context, R.color.key_flag_gray); - } else if (cursor.isVerified()) { - KeyFormattingUtils.setStatusImage( - context, - mStatusIcon, - KeyFormattingUtils.State.VERIFIED - ); - - mStatusIcon.setVisibility(View.VISIBLE); - - enabled = true; - textColor = FormattingUtils.getColorFromAttr(context, R.attr.colorText); - } else { - KeyFormattingUtils.setStatusImage( - context, - mStatusIcon, - KeyFormattingUtils.State.UNVERIFIED - ); - - mStatusIcon.setVisibility(View.VISIBLE); - - enabled = true; - textColor = FormattingUtils.getColorFromAttr(context, R.attr.colorText); - } - - mUserIdText.setTextColor(textColor); - mUserIdRestText.setTextColor(textColor); - - if (cursor.hasDuplicate()) { - String dateTime = DateUtils.formatDateTime(context, - cursor.getCreationTime(), - DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_SHOW_TIME - | DateUtils.FORMAT_SHOW_YEAR - | DateUtils.FORMAT_ABBREV_MONTH); - mCreationText.setText(context.getString(R.string.label_key_created, - dateTime)); - mCreationText.setTextColor(textColor); - mCreationText.setVisibility(View.VISIBLE); - } else { - mCreationText.setVisibility(View.GONE); - } - } - - itemView.setEnabled(enabled); - itemView.setClickable(enabled); - mChecked.setChecked(enabled && selected); - - } - - @Override - public void onClick(View v) { - switchSelected(getAdapterPosition()); - } - } - - public static class PublicKeyCursor extends CursorAdapter.KeyCursor { - public static final String[] PROJECTION; - - static { - ArrayList arr = new ArrayList<>(); - arr.addAll(Arrays.asList(KeyCursor.PROJECTION)); - arr.addAll(Arrays.asList( - KeychainContract.KeyRings.HAS_ENCRYPT, - KeychainContract.KeyRings.VERIFIED - )); - - PROJECTION = arr.toArray(new String[arr.size()]); - } - - public static PublicKeyCursor wrap(Cursor cursor) { - if (cursor != null) { - return new PublicKeyCursor(cursor); - } else { - return null; - } - } - - private PublicKeyCursor(Cursor cursor) { - super(cursor); - } - - public boolean hasEncrypt() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.HAS_ENCRYPT); - return getInt(index) != 0; - } - - public boolean isVerified() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.VERIFIED); - return getInt(index) != 0; - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectIdentityKeyAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectIdentityKeyAdapter.java deleted file mode 100644 index 66e5baee8..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectIdentityKeyAdapter.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2016 Tobias Erthal - * Copyright (C) 2014-2016 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote.ui.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.RecyclerView; -import android.text.format.DateUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import org.openintents.openpgp.util.OpenPgpUtils; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.adapter.KeyCursorAdapter; -import org.sufficientlysecure.keychain.ui.util.FormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Highlighter; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter; - - -public class SelectIdentityKeyAdapter extends KeyCursorAdapter { - private SelectSignKeyListener mListener; - - public SelectIdentityKeyAdapter(Context context, Cursor cursor) { - super(context, KeyCursor.wrap(cursor)); - } - - public void setListener(SelectSignKeyListener listener) { - mListener = listener; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new SignKeyItemHolder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.select_identity_key_item, parent, false)); - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, KeyCursor cursor, String query) { - ((SignKeyItemHolder) holder).bind(cursor, query); - } - - private class SignKeyItemHolder extends RecyclerView.ViewHolder - implements View.OnClickListener { - - private TextView userIdText; - private TextView creationText; - private ImageView statusIcon; - - SignKeyItemHolder(View itemView) { - super(itemView); - itemView.setClickable(true); - itemView.setOnClickListener(this); - - userIdText = (TextView) itemView.findViewById(R.id.select_key_item_name); - creationText = (TextView) itemView.findViewById(R.id.select_key_item_creation); - statusIcon = (ImageView) itemView.findViewById(R.id.select_key_item_status_icon); - } - - public void bind(KeyCursor cursor, String query) { - Context context = itemView.getContext(); - - { // set name and stuff, common to both key types - String name = cursor.getName(); - if (name != null) { - userIdText.setText(context.getString(R.string.use_key, name)); - } else { - String email = cursor.getEmail(); - userIdText.setText(context.getString(R.string.use_key, email)); - } - } - - { // set edit button and status, specific by key type. Note: order is important! - int textColor; - if (cursor.isRevoked()) { - KeyFormattingUtils.setStatusImage( - context, - statusIcon, - null, - KeyFormattingUtils.State.REVOKED, - R.color.key_flag_gray - ); - - itemView.setEnabled(false); - statusIcon.setVisibility(View.VISIBLE); - textColor = ContextCompat.getColor(context, R.color.key_flag_gray); - } else if (cursor.isExpired()) { - KeyFormattingUtils.setStatusImage( - context, - statusIcon, - null, - KeyFormattingUtils.State.EXPIRED, - R.color.key_flag_gray - ); - - itemView.setEnabled(false); - statusIcon.setVisibility(View.VISIBLE); - textColor = ContextCompat.getColor(context, R.color.key_flag_gray); - } else { - itemView.setEnabled(true); - statusIcon.setImageResource(R.drawable.ic_vpn_key_grey_24dp); - textColor = FormattingUtils.getColorFromAttr(context, R.attr.colorText); - } - - userIdText.setTextColor(textColor); - - String dateTime = DateUtils.formatDateTime(context, - cursor.getCreationTime(), - DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_SHOW_TIME - | DateUtils.FORMAT_SHOW_YEAR - | DateUtils.FORMAT_ABBREV_MONTH); - creationText.setText(context.getString(R.string.label_key_created, - dateTime)); - creationText.setTextColor(textColor); - creationText.setVisibility(View.VISIBLE); - } - - } - - @Override - public void onClick(View v) { - if (mListener != null) { - mListener.onSelectKeyItemClicked(getItemId()); - } - } - } - - public interface SelectSignKeyListener { - void onSelectKeyItemClicked(long masterKeyId); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectSignKeyAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectSignKeyAdapter.java deleted file mode 100644 index 45617f192..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/adapter/SelectSignKeyAdapter.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2017 Schürmann & Breitmoser GbR - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote.ui.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.RecyclerView; -import android.text.format.DateUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import org.openintents.openpgp.util.OpenPgpUtils; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.adapter.KeyCursorAdapter; -import org.sufficientlysecure.keychain.ui.util.FormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Highlighter; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter; - -public class SelectSignKeyAdapter extends KeyCursorAdapter { - private static final int VIEW_TYPE_KEY = 0; - private static final int VIEW_TYPE_DUMMY = 1; - - private SelectSignKeyListener mListener; - - public SelectSignKeyAdapter(Context context, Cursor cursor) { - super(context, KeyCursor.wrap(cursor)); - } - - public void setListener(SelectSignKeyListener listener) { - mListener = listener; - } - - @Override - public int getItemCount() { - return super.getItemCount() + 1; // received items + 1 dummy key - } - - @Override - public long getItemId(int pos) { - if (pos < super.getItemCount()) { - return super.getItemId(pos); - } else { - return RecyclerView.NO_ID; - } - } - - @Override - public int getItemViewType(int position) { - return position == super.getItemCount() ? - VIEW_TYPE_DUMMY : VIEW_TYPE_KEY; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - switch (viewType) { - case VIEW_TYPE_KEY: - return new SignKeyItemHolder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.select_sign_key_item, parent, false)); - - case VIEW_TYPE_DUMMY: - return new DummyViewHolder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.select_dummy_key_item, parent, false)); - - default: - return null; - } - - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == VIEW_TYPE_KEY) { - super.onBindViewHolder(holder, position); - } - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, KeyCursor cursor, String query) { - ((SignKeyItemHolder) holder).bind(cursor, query); - } - - private class DummyViewHolder extends RecyclerView.ViewHolder - implements View.OnClickListener { - - public DummyViewHolder(View itemView) { - super(itemView); - itemView.setClickable(true); - itemView.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - if (mListener != null) { - mListener.onCreateKeyDummyClicked(); - } - } - } - - private class SignKeyItemHolder extends RecyclerView.ViewHolder - implements View.OnClickListener { - - private TextView mUserIdText; - private TextView mUserIdRestText; - private TextView mCreationText; - private ImageView mStatusIcon; - - public SignKeyItemHolder(View itemView) { - super(itemView); - itemView.setClickable(true); - itemView.setOnClickListener(this); - - mUserIdText = itemView.findViewById(R.id.select_key_item_name); - mUserIdRestText = itemView.findViewById(R.id.select_key_item_email); - mCreationText = itemView.findViewById(R.id.select_key_item_creation); - mStatusIcon = itemView.findViewById(R.id.select_key_item_status_icon); - } - - public void bind(KeyCursor cursor, String query) { - Highlighter highlighter = new Highlighter(itemView.getContext(), query); - Context context = itemView.getContext(); - - { // set name and stuff, common to both key types - String name = cursor.getName(); - String email = cursor.getEmail(); - if (name != null) { - mUserIdText.setText(highlighter.highlight(name)); - } else { - mUserIdText.setText(R.string.user_id_no_name); - } - if (email != null) { - mUserIdRestText.setText(highlighter.highlight(email)); - mUserIdRestText.setVisibility(View.VISIBLE); - } else { - mUserIdRestText.setVisibility(View.GONE); - } - } - - { // set edit button and status, specific by key type. Note: order is important! - int textColor; - if (cursor.isRevoked()) { - KeyFormattingUtils.setStatusImage( - context, - mStatusIcon, - null, - KeyFormattingUtils.State.REVOKED, - R.color.key_flag_gray - ); - - itemView.setEnabled(false); - mStatusIcon.setVisibility(View.VISIBLE); - textColor = ContextCompat.getColor(context, R.color.key_flag_gray); - } else if (cursor.isExpired()) { - KeyFormattingUtils.setStatusImage( - context, - mStatusIcon, - null, - KeyFormattingUtils.State.EXPIRED, - R.color.key_flag_gray - ); - - itemView.setEnabled(false); - mStatusIcon.setVisibility(View.VISIBLE); - textColor = ContextCompat.getColor(context, R.color.key_flag_gray); - } else { - itemView.setEnabled(true); - mStatusIcon.setVisibility(View.GONE); - textColor = FormattingUtils.getColorFromAttr(context, R.attr.colorText); - } - - mUserIdText.setTextColor(textColor); - mUserIdRestText.setTextColor(textColor); - - if (cursor.hasDuplicate()) { - String dateTime = DateUtils.formatDateTime(context, - cursor.getCreationTime(), - DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_SHOW_TIME - | DateUtils.FORMAT_SHOW_YEAR - | DateUtils.FORMAT_ABBREV_MONTH); - mCreationText.setText(context.getString(R.string.label_key_created, - dateTime)); - mCreationText.setTextColor(textColor); - mCreationText.setVisibility(View.VISIBLE); - } else { - mCreationText.setVisibility(View.GONE); - } - } - - } - - @Override - public void onClick(View v) { - if (mListener != null) { - mListener.onSelectKeyItemClicked(getItemId()); - } - } - } - - public interface SelectSignKeyListener { - void onCreateKeyDummyClicked(); - - void onSelectKeyItemClicked(long masterKeyId); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyCursorAdapter.java deleted file mode 100644 index c46a11740..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyCursorAdapter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2017 Schürmann & Breitmoser GbR - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.support.v7.widget.RecyclerView; - -import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter; - -public abstract class KeyCursorAdapter - extends CursorAdapter { - - private String mQuery; - - public KeyCursorAdapter(Context context, C cursor){ - super(context, cursor, 0); - setHasStableIds(true); - } - - public void setQuery(String query) { - mQuery = query; - } - - @Override - public int getItemViewType(int position) { - moveCursorOrThrow(position); - return getItemViewType(getCursor()); - } - - @Override - public long getIdFromCursor(C keyCursor) { - return keyCursor.getKeyId(); - } - - @Override - public void onBindViewHolder(VH holder, int position) { - moveCursorOrThrow(position); - onBindViewHolder(holder, getCursor(), mQuery); - } - - public int getItemViewType(C keyCursor) { return 0; } - public abstract void onBindViewHolder(VH holder, C cursor, String query); -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/CursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/CursorAdapter.java deleted file mode 100644 index 562f83383..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/adapter/CursorAdapter.java +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright (C) 2017 Schürmann & Breitmoser GbR - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.util.adapter; - -import android.content.Context; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.CursorWrapper; -import android.database.DataSetObserver; -import android.os.Handler; -import android.support.v7.widget.RecyclerView; - -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter.SimpleCursor; -import timber.log.Timber; - -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; - -public abstract class CursorAdapter - extends RecyclerView.Adapter { - public static final String TAG = "CursorAdapter"; - - private C mCursor; - private Context mContext; - private boolean mDataValid; - - private ChangeObserver mChangeObserver; - private DataSetObserver mDataSetObserver; - - /** - * If set the adapter will register a content observer on the cursor and will call - * {@link #onContentChanged()} when a notification comes in. Be careful when - * using this flag: you will need to unset the current Cursor from the adapter - * to avoid leaks due to its registered observers. This flag is not needed - * when using a CursorAdapter with a - * {@link android.content.CursorLoader}. - */ - public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02; - - /** - * Constructor that allows control over auto-requery. It is recommended - * you not use this, but instead {@link #CursorAdapter(Context, SimpleCursor, int)}. - * When using this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER} - * will always be set. - * - * @param c The cursor from which to get the data. - * @param context The context - */ - public CursorAdapter(Context context, C c) { - setHasStableIds(true); - init(context, c, FLAG_REGISTER_CONTENT_OBSERVER); - } - - /** - * Recommended constructor. - * - * @param c The cursor from which to get the data. - * @param context The context - * @param flags Flags used to determine the behavior of the adapter - * @see #FLAG_REGISTER_CONTENT_OBSERVER - */ - public CursorAdapter(Context context, C c, int flags) { - setHasStableIds(true); - init(context, c, flags); - } - - private void init(Context context, C c, int flags) { - boolean cursorPresent = c != null; - mCursor = c; - mDataValid = cursorPresent; - mContext = context; - if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) { - mChangeObserver = new ChangeObserver(); - mDataSetObserver = new MyDataSetObserver(); - } else { - mChangeObserver = null; - mDataSetObserver = null; - } - - if (cursorPresent) { - if (mChangeObserver != null) c.registerContentObserver(mChangeObserver); - if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver); - } - - setHasStableIds(true); - } - - /** - * Returns the cursor. - * - * @return the cursor. - */ - public C getCursor() { - return mCursor; - } - - public Context getContext() { - return mContext; - } - - /** - * @see android.support.v7.widget.RecyclerView.Adapter#getItemCount() - */ - @Override - public int getItemCount() { - if (mDataValid && mCursor != null) { - return mCursor.getCount(); - } else { - return 0; - } - } - - public boolean hasValidData() { - mDataValid = hasOpenCursor(); - return mDataValid; - } - - private boolean hasOpenCursor() { - Cursor cursor = getCursor(); - if (cursor != null && cursor.isClosed()) { - swapCursor(null); - return false; - } - - return cursor != null; - } - - /** - * @param position Adapter position to query - * @return the id of the item - * @see android.support.v7.widget.RecyclerView.Adapter#getItemId(int) - */ - @Override - public long getItemId(int position) { - if (mDataValid && mCursor != null) { - if (moveCursor(position)) { - return getIdFromCursor(mCursor); - } else { - return RecyclerView.NO_ID; - } - } else { - return RecyclerView.NO_ID; - } - } - - /** - * Return the id of the item represented by the row the cursor - * is currently moved to. - * - * @param cursor The cursor moved to the correct position. - * @return The id of the dataset - */ - public long getIdFromCursor(C cursor) { - if (cursor != null) { - return cursor.getEntryId(); - } else { - return RecyclerView.NO_ID; - } - } - - public void moveCursorOrThrow(int position) - throws IndexOutOfBoundsException, IllegalStateException { - - if (position >= getItemCount() || position < -1) { - throw new IndexOutOfBoundsException("Position: " + position - + " is invalid for this data set!"); - } - - if (!mDataValid) { - throw new IllegalStateException("Attempt to move cursor over invalid data set!"); - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("Couldn't move cursor from position: " - + mCursor.getPosition() + " to position: " + position + "!"); - } - } - - public boolean moveCursor(int position) { - if (position >= getItemCount() || position < -1) { - Timber.w("Position: %d is invalid for this data set!"); - return false; - } - - if (!mDataValid) { - Timber.d("Attempt to move cursor over invalid data set!"); - } - - return mCursor.moveToPosition(position); - } - - /** - * Change the underlying cursor to a new cursor. If there is an existing cursor it will be - * closed. - * - * @param cursor The new cursor to be used - */ - public void changeCursor(C cursor) { - Cursor old = swapCursor(cursor); - if (old != null) { - old.close(); - } - } - - /** - * Swap in a new Cursor, returning the old Cursor. Unlike - * {@link #changeCursor(SimpleCursor)}, the returned old Cursor is not - * closed. - * - * @param newCursor The new cursor to be used. - * @return Returns the previously set Cursor, or null if there wasa not one. - * If the given new Cursor is the same instance is the previously set - * Cursor, null is also returned. - */ - public C swapCursor(C newCursor) { - if (newCursor == mCursor) { - return null; - } - - C oldCursor = mCursor; - if (oldCursor != null) { - if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver); - if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver); - } - - mCursor = newCursor; - if (newCursor != null) { - if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver); - if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver); - mDataValid = true; - // notify the observers about the new cursor - onContentChanged(); - } else { - mDataValid = false; - // notify the observers about the lack of a data set - onContentChanged(); - } - - return oldCursor; - } - - /** - *

Converts the cursor into a CharSequence. Subclasses should override this - * method to convert their results. The default implementation returns an - * empty String for null values or the default String representation of - * the value.

- * - * @param cursor the cursor to convert to a CharSequence - * @return a CharSequence representing the value - */ - public CharSequence convertToString(Cursor cursor) { - return cursor == null ? "" : cursor.toString(); - } - - /** - * Called when the {@link ContentObserver} on the cursor receives a change notification. - * The default implementation provides the auto-requery logic, but may be overridden by - * sub classes. - * - * @see ContentObserver#onChange(boolean) - */ - protected void onContentChanged() { - notifyDataSetChanged(); - } - - private class ChangeObserver extends ContentObserver { - public ChangeObserver() { - super(new Handler()); - } - - @Override - public boolean deliverSelfNotifications() { - return true; - } - - @Override - public void onChange(boolean selfChange) { - onContentChanged(); - } - } - - private class MyDataSetObserver extends DataSetObserver { - @Override - public void onChanged() { - mDataValid = true; - onContentChanged(); - } - - @Override - public void onInvalidated() { - mDataValid = false; - onContentChanged(); - } - } - - public static class SimpleCursor extends CursorWrapper { - public static final String[] PROJECTION = {"_id"}; - - public static T wrap(Cursor cursor, Class type) { - if (cursor != null) { - try { - Constructor constructor = type.getConstructor(Cursor.class); - return constructor.newInstance(cursor); - } catch (Exception e) { - Timber.e(e, "Could not create instance of cursor wrapper!"); - } - } - - return null; - } - - private HashMap mColumnIndices; - - /** - * Creates a cursor wrapper. - * - * @param cursor The underlying cursor to wrap. - */ - public SimpleCursor(Cursor cursor) { - super(cursor); - mColumnIndices = new HashMap<>(cursor.getColumnCount() * 4 / 3, 0.75f); - } - - @Override - public void close() { - mColumnIndices.clear(); - super.close(); - } - - public final int getEntryId() { - int index = getColumnIndexOrThrow("_id"); - return getInt(index); - } - - @Override - public final int getColumnIndexOrThrow(String colName) { - Integer colIndex = mColumnIndices.get(colName); - if (colIndex == null) { - colIndex = super.getColumnIndexOrThrow(colName); - mColumnIndices.put(colName, colIndex); - } else if (colIndex < 0) { - throw new IllegalArgumentException("Could not get column index for name: \"" + colName + "\""); - } - - return colIndex; - } - - @Override - public final int getColumnIndex(String colName) { - Integer colIndex = mColumnIndices.get(colName); - if (colIndex == null) { - colIndex = super.getColumnIndex(colName); - mColumnIndices.put(colName, colIndex); - } - - return colIndex; - } - } - - public static class KeyCursor extends SimpleCursor { - public static final String[] PROJECTION; - - static { - ArrayList arr = new ArrayList<>(); - arr.addAll(Arrays.asList(SimpleCursor.PROJECTION)); - arr.addAll(Arrays.asList( - KeychainContract.KeyRings.MASTER_KEY_ID, - KeychainContract.KeyRings.USER_ID, - KeychainContract.KeyRings.IS_REVOKED, - KeychainContract.KeyRings.IS_EXPIRED, - KeychainContract.KeyRings.IS_SECURE, - KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID, - KeychainContract.KeyRings.CREATION, - KeychainContract.KeyRings.NAME, - KeychainContract.KeyRings.EMAIL, - KeychainContract.KeyRings.COMMENT - )); - - PROJECTION = arr.toArray(new String[arr.size()]); - } - - public static KeyCursor wrap(Cursor cursor) { - if (cursor != null) { - return new KeyCursor(cursor); - } else { - return null; - } - } - - /** - * Creates a cursor wrapper. - * - * @param cursor The underlying cursor to wrap. - */ - protected KeyCursor(Cursor cursor) { - super(cursor); - } - - public long getKeyId() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.MASTER_KEY_ID); - return getLong(index); - } - - public String getName() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.NAME); - return getString(index); - } - - public String getEmail() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.EMAIL); - return getString(index); - } - - public String getComment() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.COMMENT); - return getString(index); - } - - public boolean hasDuplicate() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID); - return getLong(index) > 0L; - } - - public boolean isRevoked() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.IS_REVOKED); - return getInt(index) > 0; - } - - public boolean isExpired() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.IS_EXPIRED); - return getInt(index) > 0; - } - - public boolean isSecure() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.IS_SECURE); - return getInt(index) > 0; - } - - public long getCreationTime() { - int index = getColumnIndexOrThrow(KeychainContract.KeyRings.CREATION); - return getLong(index) * 1000; - } - - public Date getCreationDate() { - return new Date(getCreationTime()); - } - } -} \ No newline at end of file