aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/org/connectbot/PubkeyListActivity.java
diff options
context:
space:
mode:
authorRyan Hansberry <rhansby@gmail.com>2015-09-18 16:41:21 -0700
committerRyan Hansberry <rhansby@gmail.com>2015-09-18 16:41:21 -0700
commit9d8ea9d22dbade57f309ae3e1be4fb18cf9eb0d3 (patch)
tree508b6e3517fc2e27ee9830130775001f80a2be41 /app/src/main/java/org/connectbot/PubkeyListActivity.java
parent708e2db0bf5e3bfbb48bf94d604ef883970a2b92 (diff)
downloadconnectbot-9d8ea9d22dbade57f309ae3e1be4fb18cf9eb0d3.tar.gz
connectbot-9d8ea9d22dbade57f309ae3e1be4fb18cf9eb0d3.tar.bz2
connectbot-9d8ea9d22dbade57f309ae3e1be4fb18cf9eb0d3.zip
Convert PubkeyListActivity to AppCompat
Diffstat (limited to 'app/src/main/java/org/connectbot/PubkeyListActivity.java')
-rw-r--r--app/src/main/java/org/connectbot/PubkeyListActivity.java532
1 files changed, 316 insertions, 216 deletions
diff --git a/app/src/main/java/org/connectbot/PubkeyListActivity.java b/app/src/main/java/org/connectbot/PubkeyListActivity.java
index d8a8e70..97ef434 100644
--- a/app/src/main/java/org/connectbot/PubkeyListActivity.java
+++ b/app/src/main/java/org/connectbot/PubkeyListActivity.java
@@ -38,7 +38,6 @@ import org.connectbot.util.PubkeyUtils;
import org.openintents.intents.FileManagerIntents;
import android.app.AlertDialog;
-import android.app.ListActivity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -46,10 +45,18 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.app.AppCompatActivity;
import android.text.ClipboardManager;
import android.util.Log;
import android.view.ContextMenu;
@@ -60,8 +67,6 @@ import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TableRow;
@@ -78,7 +83,7 @@ import com.trilead.ssh2.crypto.PEMStructure;
*
* @author Kenny Root
*/
-public class PubkeyListActivity extends ListActivity implements EventListener {
+public class PubkeyListActivity extends AppCompatActivity implements EventListener {
public final static String TAG = "CB.PubkeyListActivity";
private static final int MAX_KEYFILE_SIZE = 8192;
@@ -94,6 +99,10 @@ public class PubkeyListActivity extends ListActivity implements EventListener {
protected LayoutInflater inflater = null;
+ private View mEmptyView;
+ private RecyclerView mPubkeyListView;
+ private PubkeyAdapter mAdapter;
+
protected TerminalManager bound = null;
private MenuItem onstartToggle = null;
@@ -134,23 +143,14 @@ public class PubkeyListActivity extends ListActivity implements EventListener {
super.onCreate(icicle);
setContentView(R.layout.act_pubkeylist);
- registerForContextMenu(getListView());
-
- getListView().setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
- PubkeyBean pubkey = (PubkeyBean) getListView().getItemAtPosition(position);
- boolean loaded = bound != null && bound.isKeyLoaded(pubkey.getNickname());
+ mPubkeyListView = (RecyclerView) findViewById(R.id.list);
+ mPubkeyListView.setHasFixedSize(true);
+ mPubkeyListView.setLayoutManager(new LinearLayoutManager(this));
+ mPubkeyListView.addItemDecoration(new PubkeyListItemDecoration(this));
- // handle toggling key in-memory on/off
- if (loaded) {
- bound.removeKey(pubkey.getNickname());
- updateList();
- } else {
- handleAddKey(pubkey);
- }
+ mEmptyView = findViewById(R.id.empty);
- }
- });
+ registerForContextMenu(mPubkeyListView);
clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
@@ -278,185 +278,26 @@ public class PubkeyListActivity extends ListActivity implements EventListener {
updateList();
}
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
- // Create menu to handle deleting and editing pubkey
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- final PubkeyBean pubkey = (PubkeyBean) getListView().getItemAtPosition(info.position);
-
- menu.setHeaderTitle(pubkey.getNickname());
-
- // TODO: option load/unload key from in-memory list
- // prompt for password as needed for passworded keys
-
- // cant change password or clipboard imported keys
- final boolean imported = PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType());
- final boolean loaded = bound != null && bound.isKeyLoaded(pubkey.getNickname());
-
- MenuItem load = menu.add(loaded ? R.string.pubkey_memory_unload : R.string.pubkey_memory_load);
- load.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- if (loaded) {
- bound.removeKey(pubkey.getNickname());
- updateList();
- } else {
- handleAddKey(pubkey);
- //bound.addKey(nickname, trileadKey);
- }
- return true;
- }
- });
-
- onstartToggle = menu.add(R.string.pubkey_load_on_start);
- onstartToggle.setEnabled(!pubkey.isEncrypted());
- onstartToggle.setCheckable(true);
- onstartToggle.setChecked(pubkey.isStartup());
- onstartToggle.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- // toggle onstart status
- pubkey.setStartup(!pubkey.isStartup());
- PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
- pubkeyDb.savePubkey(pubkey);
- updateList();
- return true;
- }
- });
- MenuItem copyPublicToClipboard = menu.add(R.string.pubkey_copy_public);
- copyPublicToClipboard.setEnabled(!imported);
- copyPublicToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- try {
- PublicKey pk = PubkeyUtils.decodePublic(pubkey.getPublicKey(), pubkey.getType());
- String openSSHPubkey = PubkeyUtils.convertToOpenSSHFormat(pk, pubkey.getNickname());
-
- clipboard.setText(openSSHPubkey);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return true;
- }
- });
-
- MenuItem copyPrivateToClipboard = menu.add(R.string.pubkey_copy_private);
- copyPrivateToClipboard.setEnabled(!pubkey.isEncrypted() || imported);
- copyPrivateToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- try {
- String data = null;
-
- if (imported)
- data = new String(pubkey.getPrivateKey());
- else {
- PrivateKey pk = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), pubkey.getType());
- data = PubkeyUtils.exportPEM(pk, null);
- }
-
- clipboard.setText(data);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return true;
- }
- });
-
- MenuItem changePassword = menu.add(R.string.pubkey_change_password);
- changePassword.setEnabled(!imported);
- changePassword.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- final View changePasswordView = inflater.inflate(R.layout.dia_changepassword, null, false);
- ((TableRow) changePasswordView.findViewById(R.id.old_password_prompt))
- .setVisibility(pubkey.isEncrypted() ? View.VISIBLE : View.GONE);
- new AlertDialog.Builder(PubkeyListActivity.this)
- .setView(changePasswordView)
- .setPositiveButton(R.string.button_change, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String oldPassword = ((EditText) changePasswordView.findViewById(R.id.old_password)).getText().toString();
- String password1 = ((EditText) changePasswordView.findViewById(R.id.password1)).getText().toString();
- String password2 = ((EditText) changePasswordView.findViewById(R.id.password2)).getText().toString();
-
- if (!password1.equals(password2)) {
- new AlertDialog.Builder(PubkeyListActivity.this)
- .setMessage(R.string.alert_passwords_do_not_match_msg)
- .setPositiveButton(android.R.string.ok, null)
- .create().show();
- return;
- }
-
- try {
- if (!pubkey.changePassword(oldPassword, password1))
- new AlertDialog.Builder(PubkeyListActivity.this)
- .setMessage(R.string.alert_wrong_password_msg)
- .setPositiveButton(android.R.string.ok, null)
- .create().show();
- else {
- PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
- pubkeyDb.savePubkey(pubkey);
- updateList();
- }
- } catch (Exception e) {
- Log.e(TAG, "Could not change private key password", e);
- new AlertDialog.Builder(PubkeyListActivity.this)
- .setMessage(R.string.alert_key_corrupted_msg)
- .setPositiveButton(android.R.string.ok, null)
- .create().show();
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null).create().show();
-
- return true;
- }
- });
-
- confirmUse = menu.add(R.string.pubkey_confirm_use);
- confirmUse.setCheckable(true);
- confirmUse.setChecked(pubkey.isConfirmUse());
- confirmUse.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- // toggle confirm use
- pubkey.setConfirmUse(!pubkey.isConfirmUse());
- PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
- pubkeyDb.savePubkey(pubkey);
- updateList();
- return true;
- }
- });
-
- MenuItem delete = menu.add(R.string.pubkey_delete);
- delete.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- // prompt user to make sure they really want this
- new AlertDialog.Builder(PubkeyListActivity.this)
- .setMessage(getString(R.string.delete_message, pubkey.getNickname()))
- .setPositiveButton(R.string.delete_pos, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
-
- // dont forget to remove from in-memory
- if (loaded) {
- bound.removeKey(pubkey.getNickname());
- }
-
- // delete from backend database and update gui
- PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
- pubkeyDb.deletePubkey(pubkey);
- updateList();
- }
- })
- .setNegativeButton(R.string.delete_neg, null).create().show();
-
- return true;
- }
- });
-
- }
protected void updateList() {
PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
pubkeys = pubkeyDb.allPubkeys();
- PubkeyAdapter adapter = new PubkeyAdapter(this, pubkeys);
- this.setListAdapter(adapter);
+ mAdapter = new PubkeyAdapter(this, pubkeys);
+ mPubkeyListView.setAdapter(mAdapter);
+ adjustViewVisibility();
+ }
+
+ /**
+ * If the pubkey list is empty, hides the list and shows the empty message; otherwise, shows
+ * the list and hides the empty message.
+ */
+ // TODO: this method is being duplicated but could be part of a superclass
+ private void adjustViewVisibility() {
+ boolean isEmpty = mAdapter.getItemCount() == 0;
+ mPubkeyListView.setVisibility(isEmpty ? View.GONE : View.VISIBLE);
+ mEmptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
}
@Override
@@ -589,39 +430,241 @@ public class PubkeyListActivity extends ListActivity implements EventListener {
.setNegativeButton(android.R.string.cancel, null).create().show();
}
- class PubkeyAdapter extends ArrayAdapter<PubkeyBean> {
- private List<PubkeyBean> pubkeys;
+ @VisibleForTesting
+ protected class PubkeyAdapter extends RecyclerView.Adapter<PubkeyAdapter.ViewHolder> {
+ private final LayoutInflater inflater;
+ private final List<PubkeyBean> pubkeys;
+ private final Context context;
+
+ // KLUDGE: duplication of HostListActivity?
+ class ViewHolder extends RecyclerView.ViewHolder
+ implements View.OnClickListener, View.OnCreateContextMenuListener {
+ public final ImageView icon;
+ public final TextView nickname;
+ public final TextView caption;
+ public PubkeyBean pubkey;
+
+ public ViewHolder(View v) {
+ super(v);
+ v.setOnClickListener(this);
+ v.setOnCreateContextMenuListener(this);
+
+ icon = (ImageView) v.findViewById(android.R.id.icon);
+ nickname = (TextView) v.findViewById(android.R.id.text1);
+ caption = (TextView) v.findViewById(android.R.id.text2);
+ }
- class ViewHolder {
- public TextView nickname;
- public TextView caption;
- public ImageView icon;
+ @Override
+ public void onClick(View v) {
+ boolean loaded = bound != null && bound.isKeyLoaded(pubkey.getNickname());
+
+ // handle toggling key in-memory on/off
+ if (loaded) {
+ bound.removeKey(pubkey.getNickname());
+ updateList();
+ } else {
+ handleAddKey(pubkey);
+ }
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ // Create menu to handle deleting and editing pubkey
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+
+ menu.setHeaderTitle(pubkey.getNickname());
+
+ // TODO: option load/unload key from in-memory list
+ // prompt for password as needed for passworded keys
+
+ // cant change password or clipboard imported keys
+ final boolean imported = PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType());
+ final boolean loaded = bound != null && bound.isKeyLoaded(pubkey.getNickname());
+
+ MenuItem load = menu.add(loaded ? R.string.pubkey_memory_unload : R.string.pubkey_memory_load);
+ load.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ if (loaded) {
+ bound.removeKey(pubkey.getNickname());
+ updateList();
+ } else {
+ handleAddKey(pubkey);
+ //bound.addKey(nickname, trileadKey);
+ }
+ return true;
+ }
+ });
+
+ onstartToggle = menu.add(R.string.pubkey_load_on_start);
+ onstartToggle.setEnabled(!pubkey.isEncrypted());
+ onstartToggle.setCheckable(true);
+ onstartToggle.setChecked(pubkey.isStartup());
+ onstartToggle.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ // toggle onstart status
+ pubkey.setStartup(!pubkey.isStartup());
+ PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
+ pubkeyDb.savePubkey(pubkey);
+ updateList();
+ return true;
+ }
+ });
+
+ MenuItem copyPublicToClipboard = menu.add(R.string.pubkey_copy_public);
+ copyPublicToClipboard.setEnabled(!imported);
+ copyPublicToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ try {
+ PublicKey pk = PubkeyUtils.decodePublic(pubkey.getPublicKey(), pubkey.getType());
+ String openSSHPubkey = PubkeyUtils.convertToOpenSSHFormat(pk, pubkey.getNickname());
+
+ clipboard.setText(openSSHPubkey);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+ });
+
+ MenuItem copyPrivateToClipboard = menu.add(R.string.pubkey_copy_private);
+ copyPrivateToClipboard.setEnabled(!pubkey.isEncrypted() || imported);
+ copyPrivateToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ try {
+ String data = null;
+
+ if (imported)
+ data = new String(pubkey.getPrivateKey());
+ else {
+ PrivateKey pk = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), pubkey.getType());
+ data = PubkeyUtils.exportPEM(pk, null);
+ }
+
+ clipboard.setText(data);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+ });
+
+ MenuItem changePassword = menu.add(R.string.pubkey_change_password);
+ changePassword.setEnabled(!imported);
+ changePassword.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ final View changePasswordView = inflater.inflate(R.layout.dia_changepassword, null, false);
+ ((TableRow) changePasswordView.findViewById(R.id.old_password_prompt))
+ .setVisibility(pubkey.isEncrypted() ? View.VISIBLE : View.GONE);
+ new AlertDialog.Builder(PubkeyListActivity.this)
+ .setView(changePasswordView)
+ .setPositiveButton(R.string.button_change, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String oldPassword = ((EditText) changePasswordView.findViewById(R.id.old_password)).getText().toString();
+ String password1 = ((EditText) changePasswordView.findViewById(R.id.password1)).getText().toString();
+ String password2 = ((EditText) changePasswordView.findViewById(R.id.password2)).getText().toString();
+
+ if (!password1.equals(password2)) {
+ new AlertDialog.Builder(PubkeyListActivity.this)
+ .setMessage(R.string.alert_passwords_do_not_match_msg)
+ .setPositiveButton(android.R.string.ok, null)
+ .create().show();
+ return;
+ }
+
+ try {
+ if (!pubkey.changePassword(oldPassword, password1))
+ new AlertDialog.Builder(PubkeyListActivity.this)
+ .setMessage(R.string.alert_wrong_password_msg)
+ .setPositiveButton(android.R.string.ok, null)
+ .create().show();
+ else {
+ PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
+ pubkeyDb.savePubkey(pubkey);
+ updateList();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not change private key password", e);
+ new AlertDialog.Builder(PubkeyListActivity.this)
+ .setMessage(R.string.alert_key_corrupted_msg)
+ .setPositiveButton(android.R.string.ok, null)
+ .create().show();
+ }
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null).create().show();
+
+ return true;
+ }
+ });
+
+ confirmUse = menu.add(R.string.pubkey_confirm_use);
+ confirmUse.setCheckable(true);
+ confirmUse.setChecked(pubkey.isConfirmUse());
+ confirmUse.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ // toggle confirm use
+ pubkey.setConfirmUse(!pubkey.isConfirmUse());
+ PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
+ pubkeyDb.savePubkey(pubkey);
+ updateList();
+ return true;
+ }
+ });
+
+ MenuItem delete = menu.add(R.string.pubkey_delete);
+ delete.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ // prompt user to make sure they really want this
+ new AlertDialog.Builder(PubkeyListActivity.this)
+ .setMessage(getString(R.string.delete_message, pubkey.getNickname()))
+ .setPositiveButton(R.string.delete_pos, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+
+ // dont forget to remove from in-memory
+ if (loaded) {
+ bound.removeKey(pubkey.getNickname());
+ }
+
+ // delete from backend database and update gui
+ PubkeyDatabase pubkeyDb = PubkeyDatabase.get(PubkeyListActivity.this);
+ pubkeyDb.deletePubkey(pubkey);
+ updateList();
+ }
+ })
+ .setNegativeButton(R.string.delete_neg, null).create().show();
+
+ return true;
+ }
+ });
+ }
}
public PubkeyAdapter(Context context, List<PubkeyBean> pubkeys) {
- super(context, R.layout.item_pubkey, pubkeys);
-
+ this.context = context;
this.pubkeys = pubkeys;
+ this.inflater = LayoutInflater.from(context);
}
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
-
- if (convertView == null) {
- convertView = inflater.inflate(R.layout.item_pubkey, null, false);
-
- holder = new ViewHolder();
+ public PubkeyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_pubkey, parent, false);
+ ViewHolder vh = new ViewHolder(v);
+ return vh;
+ }
- holder.nickname = (TextView) convertView.findViewById(android.R.id.text1);
- holder.caption = (TextView) convertView.findViewById(android.R.id.text2);
- holder.icon = (ImageView) convertView.findViewById(android.R.id.icon1);
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ PubkeyBean pubkey = pubkeys.get(position);
+ if (pubkey == null) {
+ // Well, something bad happened. We can't continue.
+ Log.e("PubkeyAdapter", "Pubkey bean is null!");
- convertView.setTag(holder);
- } else
- holder = (ViewHolder) convertView.getTag();
+ holder.nickname.setText("Error during lookup");
+ holder.caption.setText("see 'adb logcat' for more");
+ }
+ holder.pubkey = pubkey;
- PubkeyBean pubkey = pubkeys.get(position);
holder.nickname.setText(pubkey.getNickname());
boolean imported = PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType());
@@ -651,10 +694,67 @@ public class PubkeyListActivity extends ListActivity implements EventListener {
if (bound.isKeyLoaded(pubkey.getNickname()))
holder.icon.setImageState(new int[] { android.R.attr.state_checked }, true);
else
- holder.icon.setImageState(new int[] { }, true);
+ holder.icon.setImageState(new int[] { }, true);
}
+ }
- return convertView;
+ public PubkeyBean getItem(int position) {
+ return pubkeys.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return pubkeys.get(position).getId();
+ }
+
+ @Override
+ public int getItemCount() {
+ return pubkeys.size();
+ }
+ }
+
+ /**
+ * Item decorations for pubkey list items, which adds a divider between items and leaves a
+ * small offset at the top of the list to adhere to the Material Design spec.
+ */
+ // KLUDGE: duplication
+ private class PubkeyListItemDecoration extends RecyclerView.ItemDecoration {
+ private final int[] ATTRS = new int[]{
+ android.R.attr.listDivider
+ };
+
+ private final int TOP_LIST_OFFSET = 8;
+
+ private Drawable mDivider;
+
+ public PubkeyListItemDecoration(Context c) {
+ final TypedArray a = c.obtainStyledAttributes(ATTRS);
+ mDivider = a.getDrawable(0);
+ a.recycle();
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ final int left = parent.getPaddingLeft();
+ final int right = parent.getWidth() - parent.getPaddingRight();
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = parent.getChildAt(i);
+ final RecyclerView.LayoutParams params =
+ (RecyclerView.LayoutParams) child.getLayoutParams();
+ final int top = child.getBottom() + params.bottomMargin;
+ final int bottom = top + mDivider.getIntrinsicHeight();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(c);
+ }
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+ RecyclerView.State state) {
+ int top = parent.getChildAdapterPosition(view) == 0 ? TOP_LIST_OFFSET : 0;
+ outRect.set(0, top, 0, mDivider.getIntrinsicHeight());
}
}
}