From 2de64dd24fdc0ee59117713d270dffd97f82933a Mon Sep 17 00:00:00 2001 From: danijoo Date: Sat, 2 Jan 2016 21:44:58 +0100 Subject: [PATCH] recyclerview with notification list --- app/src/main/AndroidManifest.xml | 3 +- .../notificationlogger/MainActivity.java | 2 + .../NotificationListFragment.java | 23 --- .../notificationlogger/PackageUtils.java | 37 +++++ .../logger/LoggedNotification.java | 2 + .../CursorRecyclerViewAdapter.java | 143 ++++++++++++++++++ .../NotificationListAdapter.java | 82 ++++++++++ .../NotificationListFragment.java | 89 +++++++++++ .../{ => preferences}/BlacklistFragment.java | 2 +- .../{ => preferences}/PreferenceActivity.java | 4 +- .../{ => preferences}/PreferenceFragment.java | 3 +- .../res/layout/notification_list_fragment.xml | 22 +++ .../res/layout/notification_list_item.xml | 76 ++++++++++ app/src/main/res/values/strings.xml | 1 + build.gradle | 6 +- 15 files changed, 465 insertions(+), 30 deletions(-) delete mode 100644 app/src/main/java/net/headlezz/notificationlogger/NotificationListFragment.java create mode 100644 app/src/main/java/net/headlezz/notificationlogger/notificationlist/CursorRecyclerViewAdapter.java create mode 100644 app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListAdapter.java create mode 100644 app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListFragment.java rename app/src/main/java/net/headlezz/notificationlogger/{ => preferences}/BlacklistFragment.java (83%) rename app/src/main/java/net/headlezz/notificationlogger/{ => preferences}/PreferenceActivity.java (96%) rename app/src/main/java/net/headlezz/notificationlogger/{ => preferences}/PreferenceFragment.java (97%) create mode 100644 app/src/main/res/layout/notification_list_fragment.xml create mode 100644 app/src/main/res/layout/notification_list_item.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 527db7a..6ade294 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,7 @@ diff --git a/app/src/main/java/net/headlezz/notificationlogger/MainActivity.java b/app/src/main/java/net/headlezz/notificationlogger/MainActivity.java index 0e0748c..982cea7 100644 --- a/app/src/main/java/net/headlezz/notificationlogger/MainActivity.java +++ b/app/src/main/java/net/headlezz/notificationlogger/MainActivity.java @@ -15,6 +15,8 @@ import android.view.View; import net.headlezz.notificationlogger.createnotification.NotificationCreationFragment; import net.headlezz.notificationlogger.logger.LoggerUtils; +import net.headlezz.notificationlogger.notificationlist.NotificationListFragment; +import net.headlezz.notificationlogger.preferences.PreferenceActivity; import net.headlezz.notificationlogger.presenter.LoggerWarningPresenter; import butterknife.Bind; diff --git a/app/src/main/java/net/headlezz/notificationlogger/NotificationListFragment.java b/app/src/main/java/net/headlezz/notificationlogger/NotificationListFragment.java deleted file mode 100644 index 9e53867..0000000 --- a/app/src/main/java/net/headlezz/notificationlogger/NotificationListFragment.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.headlezz.notificationlogger; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -public class NotificationListFragment extends Fragment { - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - TextView textView = new TextView(getContext()); - textView.setGravity(Gravity.CENTER); - textView.setText(getClass().getSimpleName()); - return textView; - } - -} diff --git a/app/src/main/java/net/headlezz/notificationlogger/PackageUtils.java b/app/src/main/java/net/headlezz/notificationlogger/PackageUtils.java index 0d32c08..e48f59a 100644 --- a/app/src/main/java/net/headlezz/notificationlogger/PackageUtils.java +++ b/app/src/main/java/net/headlezz/notificationlogger/PackageUtils.java @@ -3,6 +3,10 @@ package net.headlezz.notificationlogger; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; + +import timber.log.Timber; public class PackageUtils { @@ -12,5 +16,38 @@ public class PackageUtils { return (String) pm.getApplicationLabel(appInfo); } + /** + * + * @param context + * @param packageName + * @return Drawable or Null + */ + public static Drawable getApplicationLauncherIcon(Context context, String packageName) { + try { + return context.getPackageManager().getApplicationIcon(packageName); + } catch(PackageManager.NameNotFoundException e) { + Timber.w("package not found: " + packageName); + return null; + } + } + + /** + * + * @param context + * @param packageName + * @param iconId + * @return Drawable or Null + */ + public static Drawable getApplicationDrawable(Context context, String packageName, int iconId) { + try { + Resources res = context.getPackageManager().getResourcesForApplication(packageName); + return res.getDrawable(iconId); + } catch (PackageManager.NameNotFoundException e) { + Timber.w("package not found: " + packageName); + return null; + } + + } + } diff --git a/app/src/main/java/net/headlezz/notificationlogger/logger/LoggedNotification.java b/app/src/main/java/net/headlezz/notificationlogger/logger/LoggedNotification.java index ac2d56c..6b5885b 100644 --- a/app/src/main/java/net/headlezz/notificationlogger/logger/LoggedNotification.java +++ b/app/src/main/java/net/headlezz/notificationlogger/logger/LoggedNotification.java @@ -8,6 +8,8 @@ import ckm.simple.sql_provider.annotation.SimpleSQLTable; @SimpleSQLTable(table="logged_notification", provider="NotificationProvider") public class LoggedNotification { + @SimpleSQLColumn("_id") + public long id; @SimpleSQLColumn("title") public String title; diff --git a/app/src/main/java/net/headlezz/notificationlogger/notificationlist/CursorRecyclerViewAdapter.java b/app/src/main/java/net/headlezz/notificationlogger/notificationlist/CursorRecyclerViewAdapter.java new file mode 100644 index 0000000..61345b9 --- /dev/null +++ b/app/src/main/java/net/headlezz/notificationlogger/notificationlist/CursorRecyclerViewAdapter.java @@ -0,0 +1,143 @@ +package net.headlezz.notificationlogger.notificationlist; + +/* + * Copyright (C) 2014 skyfish.jy@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import android.content.Context; +import android.database.Cursor; +import android.database.DataSetObserver; +import android.support.v7.widget.RecyclerView; + +public abstract class CursorRecyclerViewAdapter extends RecyclerView.Adapter { + + private Context mContext; + + private Cursor mCursor; + + private boolean mDataValid; + + private int mRowIdColumn; + + private DataSetObserver mDataSetObserver; + + public CursorRecyclerViewAdapter(Context context, Cursor cursor) { + mContext = context; + mCursor = cursor; + mDataValid = cursor != null; + mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1; + mDataSetObserver = new NotifyingDataSetObserver(); + if (mCursor != null) { + mCursor.registerDataSetObserver(mDataSetObserver); + } + } + + public Cursor getCursor() { + return mCursor; + } + + @Override + public int getItemCount() { + if (mDataValid && mCursor != null) { + return mCursor.getCount(); + } + return 0; + } + + @Override + public long getItemId(int position) { + if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) { + return mCursor.getLong(mRowIdColumn); + } + return 0; + } + + @Override + public void setHasStableIds(boolean hasStableIds) { + super.setHasStableIds(true); + } + + public abstract void onBindViewHolder(VH viewHolder, Cursor cursor); + + @Override + public void onBindViewHolder(VH viewHolder, int position) { + if (!mDataValid) { + throw new IllegalStateException("this should only be called when the cursor is valid"); + } + if (!mCursor.moveToPosition(position)) { + throw new IllegalStateException("couldn't move cursor to position " + position); + } + onBindViewHolder(viewHolder, mCursor); + } + + /** + * Change the underlying cursor to a new cursor. If there is an existing cursor it will be + * closed. + */ + public void changeCursor(Cursor cursor) { + Cursor old = swapCursor(cursor); + if (old != null) { + old.close(); + } + } + + /** + * Swap in a new Cursor, returning the old Cursor. Unlike + * {@link #changeCursor(Cursor)}, the returned old Cursor is not + * closed. + */ + public Cursor swapCursor(Cursor newCursor) { + if (newCursor == mCursor) { + return null; + } + final Cursor oldCursor = mCursor; + if (oldCursor != null && mDataSetObserver != null) { + oldCursor.unregisterDataSetObserver(mDataSetObserver); + } + mCursor = newCursor; + if (mCursor != null) { + if (mDataSetObserver != null) { + mCursor.registerDataSetObserver(mDataSetObserver); + } + mRowIdColumn = newCursor.getColumnIndexOrThrow("_id"); + mDataValid = true; + notifyDataSetChanged(); + } else { + mRowIdColumn = -1; + mDataValid = false; + notifyDataSetChanged(); + //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter + } + return oldCursor; + } + + private class NotifyingDataSetObserver extends DataSetObserver { + @Override + public void onChanged() { + super.onChanged(); + mDataValid = true; + notifyDataSetChanged(); + } + + @Override + public void onInvalidated() { + super.onInvalidated(); + mDataValid = false; + notifyDataSetChanged(); + //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter + } + } +} diff --git a/app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListAdapter.java b/app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListAdapter.java new file mode 100644 index 0000000..a28e5d9 --- /dev/null +++ b/app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListAdapter.java @@ -0,0 +1,82 @@ +package net.headlezz.notificationlogger.notificationlist; + +import android.content.Context; +import android.database.Cursor; +import android.graphics.drawable.Drawable; +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 net.headlezz.notificationlogger.PackageUtils; +import net.headlezz.notificationlogger.R; +import net.headlezz.notificationlogger.logger.LoggedNotification; +import net.headlezz.notificationlogger.logger.Logged_notificationTable; + +import butterknife.Bind; +import butterknife.ButterKnife; + + +public class NotificationListAdapter extends CursorRecyclerViewAdapter { + + class NotificationViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.notification_item_message) + TextView tvMessage; + + @Bind(R.id.notification_item_title) + TextView tvTitle; + + @Bind(R.id.notification_item_appName) + TextView tvAppName; + + @Bind(R.id.notification_item_date) + TextView tvDate; + + @Bind(R.id.notification_item_appIcon) + ImageView ivAppIcon; + + @Bind(R.id.notification_item_smallIcon) + ImageView ivSmallIcon; + + public NotificationViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + + public void setNotification(LoggedNotification n) { + Context context = itemView.getContext(); + + tvMessage.setText(n.message); + tvTitle.setText(n.title); + tvAppName.setText(n.appName); + CharSequence formattedDate = DateUtils.getRelativeTimeSpanString(n.date.getTime(), System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS, DateUtils.FORMAT_ABBREV_ALL); + tvDate.setText(formattedDate); + + Drawable appIcon = PackageUtils.getApplicationLauncherIcon(context, n.packageName); + ivAppIcon.setImageDrawable(appIcon); + + Drawable smallIcon = PackageUtils.getApplicationDrawable(context, n.packageName, n.smallIconId); + ivSmallIcon.setImageDrawable(smallIcon); + } + } + + public NotificationListAdapter(Context context, Cursor cursor) { + super(context, cursor); + } + + @Override + public void onBindViewHolder(NotificationViewHolder viewHolder, Cursor cursor) { + LoggedNotification n = Logged_notificationTable.getRow(cursor, false); + viewHolder.setNotification(n); + } + + @Override + public NotificationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.notification_list_item, parent, false); + return new NotificationViewHolder(v); + } +} diff --git a/app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListFragment.java b/app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListFragment.java new file mode 100644 index 0000000..a2fed8c --- /dev/null +++ b/app/src/main/java/net/headlezz/notificationlogger/notificationlist/NotificationListFragment.java @@ -0,0 +1,89 @@ +package net.headlezz.notificationlogger.notificationlist; + +import android.database.Cursor; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import net.headlezz.notificationlogger.R; +import net.headlezz.notificationlogger.logger.Logged_notificationTable; + +import butterknife.Bind; +import butterknife.ButterKnife; +import timber.log.Timber; + +public class NotificationListFragment extends Fragment implements LoaderManager.LoaderCallbacks { + + final int LOADER_ID = 124; + + @Bind(R.id.nList_emptyView) + View mEmptyView; + + @Bind(R.id.nList_notificationList) + RecyclerView mNotificationList; + + private NotificationListAdapter mAdapter; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.notification_list_fragment, container, false); + ButterKnife.bind(this, view); + mNotificationList.setLayoutManager(new LinearLayoutManager(getContext())); + + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mAdapter = new NotificationListAdapter(getContext(), null); + mNotificationList.setAdapter(mAdapter); + getLoaderManager().initLoader(LOADER_ID, Bundle.EMPTY, this); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + Timber.d("Loader created."); + return new CursorLoader( + getContext(), + Logged_notificationTable.CONTENT_URI, + null, + null, + null, + null + ); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + Timber.d("Loader finished. " + data.getCount() + " items."); + mAdapter.changeCursor(data); + checkIfEmpty(); + } + + @Override + public void onLoaderReset(Loader loader) { + Timber.d("Loader reset."); + mAdapter.changeCursor(null); + checkIfEmpty(); + } + + private void checkIfEmpty() { + if(mAdapter.getItemCount() == 0) { + mEmptyView.setVisibility(View.VISIBLE); + mNotificationList.setVisibility(View.GONE); + } else { + mEmptyView.setVisibility(View.GONE); + mNotificationList.setVisibility(View.VISIBLE); + } + } +} diff --git a/app/src/main/java/net/headlezz/notificationlogger/BlacklistFragment.java b/app/src/main/java/net/headlezz/notificationlogger/preferences/BlacklistFragment.java similarity index 83% rename from app/src/main/java/net/headlezz/notificationlogger/BlacklistFragment.java rename to app/src/main/java/net/headlezz/notificationlogger/preferences/BlacklistFragment.java index aa9ac2e..1d37aba 100644 --- a/app/src/main/java/net/headlezz/notificationlogger/BlacklistFragment.java +++ b/app/src/main/java/net/headlezz/notificationlogger/preferences/BlacklistFragment.java @@ -1,4 +1,4 @@ -package net.headlezz.notificationlogger; +package net.headlezz.notificationlogger.preferences; import android.app.Activity; import android.support.v4.app.Fragment; diff --git a/app/src/main/java/net/headlezz/notificationlogger/PreferenceActivity.java b/app/src/main/java/net/headlezz/notificationlogger/preferences/PreferenceActivity.java similarity index 96% rename from app/src/main/java/net/headlezz/notificationlogger/PreferenceActivity.java rename to app/src/main/java/net/headlezz/notificationlogger/preferences/PreferenceActivity.java index 9fbc58f..edb48a0 100644 --- a/app/src/main/java/net/headlezz/notificationlogger/PreferenceActivity.java +++ b/app/src/main/java/net/headlezz/notificationlogger/preferences/PreferenceActivity.java @@ -1,4 +1,4 @@ -package net.headlezz.notificationlogger; +package net.headlezz.notificationlogger.preferences; import android.os.Bundle; import android.support.annotation.Nullable; @@ -8,6 +8,8 @@ import android.support.v7.widget.Toolbar; import com.mikepenz.aboutlibraries.LibsBuilder; import com.mikepenz.aboutlibraries.ui.LibsSupportFragment; +import net.headlezz.notificationlogger.R; + import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/net/headlezz/notificationlogger/PreferenceFragment.java b/app/src/main/java/net/headlezz/notificationlogger/preferences/PreferenceFragment.java similarity index 97% rename from app/src/main/java/net/headlezz/notificationlogger/PreferenceFragment.java rename to app/src/main/java/net/headlezz/notificationlogger/preferences/PreferenceFragment.java index bc0a6fc..0fc594a 100644 --- a/app/src/main/java/net/headlezz/notificationlogger/PreferenceFragment.java +++ b/app/src/main/java/net/headlezz/notificationlogger/preferences/PreferenceFragment.java @@ -1,4 +1,4 @@ -package net.headlezz.notificationlogger; +package net.headlezz.notificationlogger.preferences; import android.app.Activity; import android.content.ContentResolver; @@ -10,6 +10,7 @@ import android.support.v7.app.AlertDialog; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; +import net.headlezz.notificationlogger.R; import net.headlezz.notificationlogger.logger.Logged_notificationTable; public class PreferenceFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener { diff --git a/app/src/main/res/layout/notification_list_fragment.xml b/app/src/main/res/layout/notification_list_fragment.xml new file mode 100644 index 0000000..178eeff --- /dev/null +++ b/app/src/main/res/layout/notification_list_fragment.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/notification_list_item.xml b/app/src/main/res/layout/notification_list_item.xml new file mode 100644 index 0000000..008ba41 --- /dev/null +++ b/app/src/main/res/layout/notification_list_item.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 501025c..3848b6e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,6 +44,7 @@ Notification sheduled for %1$s Undo + No notifications found. Alarm diff --git a/build.gradle b/build.gradle index 06a33d2..2152497 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,6 @@ allprojects { } } -task clean(type: Delete) { - delete rootProject.buildDir -} +//task clean(type: Delete) { +// delete rootProject.buildDir +//}