diff options
author | Jason Monk <jmonk@google.com> | 2016-08-11 11:16:36 -0400 |
---|---|---|
committer | Jason Monk <jmonk@google.com> | 2016-08-11 11:16:36 -0400 |
commit | 8752b6579fa2cc0659ed20b8e9e0ac606cdce2ed (patch) | |
tree | 4a5f0fd803a3aff510b66efd3e35e131567d0bb1 | |
parent | 002df26c21a78353d33705bb076ac61a09400095 (diff) | |
download | experimental-8752b6579fa2cc0659ed20b8e9e0ac606cdce2ed.tar.gz |
Fix build and switch to RecyclerView
- Fix build
- Switch to recyclerView
- Add swipe to dismiss
- Don't try to cache views, causing proboblems and likely not
needed anymore
- Make views look more like notification panel.
Change-Id: I6620c247405c077fa90942693c884cf5b1e5b811
5 files changed, 128 insertions, 93 deletions
diff --git a/NotificationListenerSample/Android.mk b/NotificationListenerSample/Android.mk index 5075a96..9ab4b62 100644 --- a/NotificationListenerSample/Android.mk +++ b/NotificationListenerSample/Android.mk @@ -18,13 +18,22 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \ + frameworks/support/v7/appcompat/res \ + frameworks/support/v7/recyclerview/res + +LOCAL_AAPT_FLAGS := --auto-add-overlay \ + --extra-packages android.support.v7.appcompat:android.support.v7.recyclerview + LOCAL_MODULE_TAGS := optional LOCAL_AAPT_FLAGS += -c mdpi,hdpi,xhdpi LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 +LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 \ + android-support-v7-recyclerview \ + android-support-v7-appcompat LOCAL_PACKAGE_NAME := NotificationListenerSample LOCAL_CERTIFICATE := platform diff --git a/NotificationListenerSample/res/layout/item.xml b/NotificationListenerSample/res/layout/item.xml index 2d9a5ed..3c505ac 100644 --- a/NotificationListenerSample/res/layout/item.xml +++ b/NotificationListenerSample/res/layout/item.xml @@ -14,19 +14,12 @@ limitations under the License. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_height="match_parent" - android:layout_width="wrap_content" - android:padding="4dp"> + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:background="@android:color/white"> <FrameLayout android:id="@+id/remote_view" - android:layout_height="match_parent" - android:layout_width="wrap_content" - android:onClick="launch" - /> - <ImageButton android:id="@+id/dismiss" - android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="top|end" - android:src="@drawable/dialog_ic_dismiss" - android:onClick="dismiss" + android:layout_width="match_parent" + android:onClick="launch" /> -</FrameLayout>
\ No newline at end of file +</FrameLayout> diff --git a/NotificationListenerSample/res/layout/main.xml b/NotificationListenerSample/res/layout/main.xml index 9cc681c..12b230f 100644 --- a/NotificationListenerSample/res/layout/main.xml +++ b/NotificationListenerSample/res/layout/main.xml @@ -14,45 +14,51 @@ limitations under the License. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:padding="12dp" - > - <ListView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="12dp" + > + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:paddingBottom="12dp" + android:layout_weight="1"> + <android.support.v7.widget.RecyclerView android:id="@android:id/list" android:layout_width="match_parent" - android:layout_height="0dp" - android:padding="4dp" + android:layout_height="wrap_content" android:layout_marginBottom="16dp" - android:text="@string/working_as_intended" - android:layout_weight="1" - android:choiceMode="singleChoice" + android:background="#eeeeee" + android:elevation="4dp" /> + </FrameLayout> <TextView android:id="@android:id/empty" - android:layout_width="match_parent" - android:layout_height="0dp" - android:padding="4dp" - android:layout_marginBottom="16dp" - android:text="@string/working_as_intended" - android:layout_weight="1" - /> + android:layout_width="match_parent" + android:layout_height="0dp" + android:padding="16dp" + android:layout_marginBottom="16dp" + android:text="@string/working_as_intended" + android:layout_weight="1" + /> + <Button - android:id="@+id/launch_settings" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/launch_to_disable" - android:onClick="launchSettings" - android:layout_weight="0" - /> + android:id="@+id/launch_settings" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/launch_to_disable" + android:onClick="launchSettings" + android:layout_gravity="bottom" + /> <Button - android:id="@+id/snooze" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/snooze" - android:onClick="snooze" - android:layout_weight="0" - /> + android:id="@+id/snooze" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/snooze" + android:onClick="snooze" + android:layout_gravity="bottom" + /> </LinearLayout> diff --git a/NotificationListenerSample/src/com/android/example/notificationlistener/Listener.java b/NotificationListenerSample/src/com/android/example/notificationlistener/Listener.java index 4a65e6a..43979d0 100644 --- a/NotificationListenerSample/src/com/android/example/notificationlistener/Listener.java +++ b/NotificationListenerSample/src/com/android/example/notificationlistener/Listener.java @@ -80,7 +80,7 @@ public class Listener extends NotificationListenerService { NotificationListenerService.requestRebind( ComponentName.createRelative(context.getPackageName(), Listener.class.getCanonicalName())); - } catch (RemoteException e) { + } catch (Exception e) { Log.e(TAG, "failed to rebind service", e); } } @@ -238,7 +238,7 @@ public class Listener extends NotificationListenerService { Log.d(TAG, "trying to snooze"); try { requestUnbind(); - } catch (RemoteException e) { + } catch (Exception e) { Log.e(TAG, "failed to unbind service", e); } break; diff --git a/NotificationListenerSample/src/com/android/example/notificationlistener/NotificationListenerActivity.java b/NotificationListenerSample/src/com/android/example/notificationlistener/NotificationListenerActivity.java index c5016af..b171811 100644 --- a/NotificationListenerSample/src/com/android/example/notificationlistener/NotificationListenerActivity.java +++ b/NotificationListenerSample/src/com/android/example/notificationlistener/NotificationListenerActivity.java @@ -15,6 +15,7 @@ */ package com.android.example.notificationlistener; +import android.app.Activity; import android.app.AlertDialog; import android.app.ListActivity; import android.app.Notification; @@ -27,7 +28,13 @@ import android.os.Bundle; import android.provider.Settings.Secure; import android.service.notification.StatusBarNotification; import android.support.v4.content.LocalBroadcastManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; @@ -39,7 +46,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -public class NotificationListenerActivity extends ListActivity { +public class NotificationListenerActivity extends Activity { private static final String LISTENER_PATH = "com.android.example.notificationlistener/" + "com.android.example.notificationlistener.Listener"; private static final String TAG = "NotificationListenerActivity"; @@ -72,7 +79,36 @@ public class NotificationListenerActivity extends ListActivity { mSnoozeButton = (Button) findViewById(R.id.snooze); mEmptyText = (TextView) findViewById(android.R.id.empty); mStatusAdaptor = new StatusAdaptor(this); - setListAdapter(mStatusAdaptor); + RecyclerView list = (RecyclerView) findViewById(android.R.id.list); + list.setLayoutManager(new LinearLayoutManager(this)); + list.setAdapter(mStatusAdaptor); + + ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SimpleCallback(0, + ItemTouchHelper.RIGHT) { + @Override + public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { + List<StatusBarNotification> notifications = mStatusAdaptor.mNotifications; + int position = viewHolder.getAdapterPosition(); + if (notifications == null || position >= notifications.size()) { + return 0; + } + StatusBarNotification notification = notifications.get(position); + return notification.isClearable() ? super.getMovementFlags(recyclerView, viewHolder) + : 0; + } + + @Override + public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, + ViewHolder target) { + return false; + } + + @Override + public void onSwiped(ViewHolder viewHolder, int direction) { + dismiss(viewHolder.itemView); + } + }); + itemTouchHelper.attachToRecyclerView(list); } @Override @@ -171,17 +207,20 @@ public class NotificationListenerActivity extends ListActivity { final List<StatusBarNotification> notifications = Listener.getNotifications(); if (notifications != null) { mStatusAdaptor.setData(notifications); + findViewById(android.R.id.empty).setVisibility(notifications.size() == 0 + ? View.VISIBLE : View.GONE); + } else { + findViewById(android.R.id.empty).setVisibility(View.VISIBLE); } mStatusAdaptor.update(key); } - private class StatusAdaptor extends BaseAdapter { + private class StatusAdaptor extends RecyclerView.Adapter<Holder> { private final Context mContext; private List<StatusBarNotification> mNotifications; private HashMap<String, Long> mKeyToId; private HashSet<String> mKeys; private long mNextId; - private HashMap<String, View> mRecycledViews; private String mUpdateKey; public StatusAdaptor(Context context) { @@ -189,44 +228,35 @@ public class NotificationListenerActivity extends ListActivity { mKeyToId = new HashMap<String, Long>(); mKeys = new HashSet<String>(); mNextId = 0; - mRecycledViews = new HashMap<String, View>(); + setHasStableIds(true); } @Override - public int getCount() { + public int getItemCount() { return mNotifications == null ? 0 : mNotifications.size(); } @Override - public Object getItem(int position) { - return mNotifications.get(position); - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override public long getItemId(int position) { final StatusBarNotification sbn = mNotifications.get(position); final String key = sbn.getKey(); if (!mKeyToId.containsKey(key)) { mKeyToId.put(key, mNextId); - mNextId ++; + mNextId++; } return mKeyToId.get(key); } @Override - public View getView(int position, View view, ViewGroup list) { - if (view == null) { - view = View.inflate(mContext, R.layout.item, null); - } - FrameLayout container = (FrameLayout) view.findViewById(R.id.remote_view); - View dismiss = view.findViewById(R.id.dismiss); + public Holder onCreateViewHolder(ViewGroup parent, int viewType) { + return new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, + parent, false)); + } + + @Override + public void onBindViewHolder(Holder holder, int position) { + FrameLayout container = holder.container; StatusBarNotification sbn = mNotifications.get(position); - View child; if (container.getTag() instanceof StatusBarNotification && container.getChildCount() > 0) { // recycle the view @@ -237,40 +267,27 @@ public class NotificationListenerActivity extends ListActivity { } else { View content = container.getChildAt(0); container.removeView(content); - mRecycledViews.put(old.getKey(), content); } } - child = mRecycledViews.get(sbn.getKey()); - if (child == null) { - Notification.Builder builder = - Notification.Builder.recoverBuilder(mContext, sbn.getNotification()); - child = builder.createContentView().apply(mContext, null); - } + Notification.Builder builder = + Notification.Builder.recoverBuilder(mContext, sbn.getNotification()); + View child = builder.createContentView().apply(mContext, null); container.setTag(sbn); + holder.itemView.setTag(sbn); container.removeAllViews(); container.addView(child); - dismiss.setVisibility(sbn.isClearable() ? View.VISIBLE : View.GONE); - dismiss.setTag(sbn); - return view; } public void update(String key) { if (mNotifications != null) { synchronized (mNotifications) { - mKeys.clear(); for (int i = 0; i < mNotifications.size(); i++) { - mKeys.add(mNotifications.get(i).getKey()); + if (mNotifications.get(i).getKey().equals(key)) { + Log.d(TAG, "notifyItemChanged " + i); + notifyItemChanged(i); + } } - mKeyToId.keySet().retainAll(mKeys); } - if (key == null) { - mRecycledViews.clear(); - } else { - mUpdateKey = key; - mRecycledViews.remove(key); - } - Log.d(TAG, "notifyDataSetChanged"); - notifyDataSetChanged(); } else { Log.d(TAG, "missed and update"); } @@ -278,6 +295,16 @@ public class NotificationListenerActivity extends ListActivity { public void setData(List<StatusBarNotification> notifications) { mNotifications = notifications; + notifyDataSetChanged(); + } + } + + private static class Holder extends RecyclerView.ViewHolder { + private final FrameLayout container; + + public Holder(View itemView) { + super(itemView); + container = (FrameLayout) itemView.findViewById(R.id.remote_view); } } } |