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
+//}