backlist feature
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package net.headlezz.notificationlogger.logger;
|
||||
|
||||
|
||||
import ckm.simple.sql_provider.annotation.SimpleSQLColumn;
|
||||
import ckm.simple.sql_provider.annotation.SimpleSQLTable;
|
||||
|
||||
@SimpleSQLTable(table="blacklist", provider="NotificationProvider")
|
||||
public class BlacklistItem {
|
||||
|
||||
@SimpleSQLColumn("_id")
|
||||
public long id;
|
||||
|
||||
@SimpleSQLColumn("package_name")
|
||||
public String packageName;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import android.app.Notification;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
@@ -49,18 +50,37 @@ public class NotificationLoggerService extends NotificationListenerService imple
|
||||
public void onNotificationPosted(StatusBarNotification sbn) {
|
||||
super.onNotificationPosted(sbn);
|
||||
|
||||
if(!isEnabled) {
|
||||
if (!isEnabled) {
|
||||
Timber.d("Notification posted but logger is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LoggedNotification ln = buildLoggedNotification(sbn);
|
||||
getApplicationContext().getContentResolver().insert(
|
||||
Logged_notificationTable.CONTENT_URI,
|
||||
Logged_notificationTable.getContentValues(ln, false)
|
||||
if (isBlacklisted(ln)) {
|
||||
Timber.d("App blacklisted. Notification not logged");
|
||||
} else {
|
||||
getApplicationContext().getContentResolver().insert(
|
||||
Logged_notificationTable.CONTENT_URI,
|
||||
Logged_notificationTable.getContentValues(ln, false)
|
||||
);
|
||||
Timber.d(String.format("Notificaton logged (id: %d)", ln.notificationId));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBlacklisted(LoggedNotification ln) {
|
||||
Cursor cursor = getApplicationContext().getContentResolver().query(
|
||||
BlacklistTable.CONTENT_URI,
|
||||
null,
|
||||
BlacklistTable.FIELD_PACKAGE_NAME + " = ?",
|
||||
new String[] { String.valueOf(ln.packageName) },
|
||||
null,
|
||||
null
|
||||
);
|
||||
Timber.d(String.format("Notificaton logged (id: %d)", ln.notificationId));
|
||||
boolean isBlacklisted = cursor != null && cursor.getCount() > 0;
|
||||
if(cursor != null)
|
||||
cursor.close();
|
||||
return isBlacklisted;
|
||||
}
|
||||
|
||||
private LoggedNotification buildLoggedNotification(StatusBarNotification sbn) {
|
||||
@@ -85,9 +105,9 @@ public class NotificationLoggerService extends NotificationListenerService imple
|
||||
String title = extras.getString("android.title", "");
|
||||
String message = extras.getCharSequence("android.text", "").toString();
|
||||
|
||||
if(message.isEmpty() && notification.tickerText != null)
|
||||
if (message.isEmpty() && notification.tickerText != null)
|
||||
message = notification.tickerText.toString();
|
||||
if(message.isEmpty() && extras.containsKey("android.infoText"))
|
||||
if (message.isEmpty() && extras.containsKey("android.infoText"))
|
||||
message = extras.get("android.infoText").toString();
|
||||
|
||||
LoggedNotification ln = new LoggedNotification();
|
||||
@@ -104,7 +124,7 @@ public class NotificationLoggerService extends NotificationListenerService imple
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if(key.equals("pref_logging_enabled")) {
|
||||
if (key.equals("pref_logging_enabled")) {
|
||||
isEnabled = sharedPreferences.getBoolean("pref_logging_enabled", true);
|
||||
Timber.d("Logging is now " + isEnabled);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package net.headlezz.notificationlogger.preferences;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.headlezz.notificationlogger.PackageUtils;
|
||||
import net.headlezz.notificationlogger.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class AppsAdapter extends BaseAdapter {
|
||||
|
||||
private List<String> mPackageNames;
|
||||
|
||||
class ViewHolder {
|
||||
TextView tvName;
|
||||
TextView tvPackageName;
|
||||
ImageView ivIcon;
|
||||
}
|
||||
|
||||
public AppsAdapter(List<String> packageNames) {
|
||||
mPackageNames = packageNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mPackageNames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mPackageNames.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
ViewHolder viewHolder;
|
||||
if(convertView == null) {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.apps_adapter_view, parent, false);
|
||||
viewHolder = new ViewHolder();
|
||||
convertView.setTag(viewHolder);
|
||||
viewHolder.ivIcon = (ImageView) convertView.findViewById(android.R.id.icon1);
|
||||
viewHolder.tvName = (TextView) convertView.findViewById(android.R.id.text1);
|
||||
viewHolder.tvPackageName = (TextView) convertView.findViewById(android.R.id.text2);
|
||||
} else
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
|
||||
String packageName = (String) getItem(position);
|
||||
viewHolder.tvPackageName.setText(packageName);
|
||||
try {
|
||||
viewHolder.tvName.setText(PackageUtils.getAppName(convertView.getContext(), packageName));
|
||||
viewHolder.ivIcon.setImageDrawable(PackageUtils.getApplicationLauncherIcon(convertView.getContext(), packageName));
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Timber.d("app name not found", e);
|
||||
viewHolder.tvName.setText("");
|
||||
viewHolder.ivIcon.setImageDrawable(null);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,200 @@
|
||||
package net.headlezz.notificationlogger.preferences;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
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.app.AlertDialog;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class BlacklistFragment extends Fragment {
|
||||
import net.headlezz.notificationlogger.PackageUtils;
|
||||
import net.headlezz.notificationlogger.R;
|
||||
import net.headlezz.notificationlogger.logger.BlacklistItem;
|
||||
import net.headlezz.notificationlogger.logger.BlacklistTable;
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class BlacklistFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener, BlacklistListAdapter.BlacklistCallbacks {
|
||||
|
||||
final int LOADER_ID = 1752;
|
||||
|
||||
@Bind(R.id.blacklistList_emptyView)
|
||||
View mEmptyView;
|
||||
|
||||
@Bind(R.id.blacklistList_list)
|
||||
RecyclerView mBlacklistList;
|
||||
|
||||
@Bind(R.id.blacklistList_fab)
|
||||
FloatingActionButton mFab;
|
||||
|
||||
BlacklistListAdapter mAdapter;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.blacklist_frag, container, false);
|
||||
ButterKnife.bind(this, view);
|
||||
mBlacklistList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
mFab.setOnClickListener(this);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mAdapter = new BlacklistListAdapter(getContext(), null, this);
|
||||
mBlacklistList.setAdapter(mAdapter);
|
||||
getLoaderManager().initLoader(LOADER_ID, Bundle.EMPTY, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
Timber.d("blacklistloader created");
|
||||
return new CursorLoader(getContext(),
|
||||
BlacklistTable.CONTENT_URI,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
BlacklistTable.FIELD_PACKAGE_NAME + " DESC");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
Timber.d("blacklistloader finished: " + data.getCount() + " items.");
|
||||
mAdapter.changeCursor(data);
|
||||
checkEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
Timber.d("blacklistloader reset");
|
||||
mAdapter.changeCursor(null);
|
||||
checkEmpty();
|
||||
}
|
||||
|
||||
private void checkEmpty() {
|
||||
if(mAdapter.getItemCount() == 0) {
|
||||
mEmptyView.setVisibility(View.VISIBLE);
|
||||
mBlacklistList.setVisibility(View.GONE);
|
||||
} else {
|
||||
mEmptyView.setVisibility(View.GONE);
|
||||
mBlacklistList.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
loadBlacklistPickerDialog();
|
||||
}
|
||||
|
||||
private void loadBlacklistPickerDialog() {
|
||||
// disable fab until the list is loaded
|
||||
mFab.setEnabled(false);
|
||||
new AsyncTask<Void, Void, List<String>>() {
|
||||
|
||||
@Override
|
||||
protected List<String> doInBackground(Void... params) {
|
||||
PackageManager pm = getContext().getPackageManager();
|
||||
List<ApplicationInfo> installedApps = pm.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||
List<String> appPackages = new ArrayList<>();
|
||||
for(ApplicationInfo appInfo : installedApps) {
|
||||
appPackages.add(appInfo.packageName);
|
||||
}
|
||||
Collections.sort(appPackages, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String lhs, String rhs) {
|
||||
String lhsName, rhsName;
|
||||
try {
|
||||
lhsName = PackageUtils.getAppName(getContext(), lhs);
|
||||
rhsName = PackageUtils.getAppName(getContext(), rhs);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return 0;
|
||||
}
|
||||
return lhsName.compareTo(rhsName);
|
||||
}
|
||||
});
|
||||
return appPackages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final List<String> packageNames) {
|
||||
mFab.setEnabled(true);
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(getContext().getString(R.string.blacklist_add_dialog_title))
|
||||
.setAdapter(new AppsAdapter(packageNames), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String packageName = packageNames.get(which);
|
||||
BlacklistItem item = new BlacklistItem();
|
||||
item.packageName = packageName;
|
||||
ContentResolver cr = getContext().getContentResolver();
|
||||
Cursor cursor = cr.query(
|
||||
BlacklistTable.CONTENT_URI,
|
||||
null,
|
||||
BlacklistTable.FIELD_PACKAGE_NAME + " = ?",
|
||||
new String[] { packageName },
|
||||
null,
|
||||
null
|
||||
);
|
||||
boolean blacklisted = cursor.getCount() > 0;
|
||||
cursor.close();
|
||||
if(!blacklisted) {
|
||||
getContext().getContentResolver().insert(
|
||||
BlacklistTable.CONTENT_URI,
|
||||
BlacklistTable.getContentValues(item, false)
|
||||
);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
})
|
||||
.create().show();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlacklistItemLongClicked(final BlacklistItem item) {
|
||||
String appName;
|
||||
try {
|
||||
appName = PackageUtils.getAppName(getContext(), item.packageName);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
appName = item.packageName;
|
||||
}
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(getContext().getString(R.string.blacklist_dialog_remove_title))
|
||||
.setMessage(getContext().getString(R.string.blacklist_fragment_remove_message, appName))
|
||||
.setPositiveButton(getContext().getString(R.string.ok), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
getContext().getContentResolver().delete(
|
||||
BlacklistTable.CONTENT_URI,
|
||||
BlacklistTable.FIELD_PACKAGE_NAME + " = ?",
|
||||
new String[] {String.valueOf(item.packageName)}
|
||||
);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(getContext().getString(R.string.cancel), null)
|
||||
.create().show();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package net.headlezz.notificationlogger.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.headlezz.notificationlogger.PackageUtils;
|
||||
import net.headlezz.notificationlogger.logger.BlacklistItem;
|
||||
import net.headlezz.notificationlogger.logger.BlacklistTable;
|
||||
import net.headlezz.notificationlogger.notificationlist.CursorRecyclerViewAdapter;
|
||||
|
||||
public class BlacklistListAdapter extends CursorRecyclerViewAdapter implements View.OnLongClickListener {
|
||||
|
||||
interface BlacklistCallbacks {
|
||||
void onBlacklistItemLongClicked(BlacklistItem item);
|
||||
}
|
||||
|
||||
class BlacklistViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
TextView mPackageName;
|
||||
TextView mAppName;
|
||||
|
||||
public BlacklistViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
mAppName = (TextView) itemView.findViewById(android.R.id.text1);
|
||||
mPackageName = (TextView) itemView.findViewById(android.R.id.text2);
|
||||
}
|
||||
|
||||
public void setBlacklistItem(BlacklistItem item) {
|
||||
mPackageName.setText(item.packageName);
|
||||
String appName;
|
||||
try {
|
||||
appName = PackageUtils.getAppName(
|
||||
itemView.getContext(),
|
||||
item.packageName
|
||||
);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
appName = "";
|
||||
}
|
||||
mAppName.setText(appName);
|
||||
itemView.setTag(item);
|
||||
}
|
||||
}
|
||||
|
||||
BlacklistCallbacks mCallbacks;
|
||||
|
||||
public BlacklistListAdapter(Context context, Cursor cursor, BlacklistCallbacks cb) {
|
||||
super(context, cursor);
|
||||
mCallbacks = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, Cursor cursor) {
|
||||
BlacklistItem item = BlacklistTable.getRow(cursor, false);
|
||||
((BlacklistViewHolder) viewHolder).setBlacklistItem(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_2, parent, false);
|
||||
view.setOnLongClickListener(this);
|
||||
return new BlacklistViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
BlacklistItem item = (BlacklistItem) v.getTag();
|
||||
mCallbacks.onBlacklistItemLongClicked(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,17 @@ package net.headlezz.notificationlogger.preferences;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.DialogInterface;
|
||||
import android.database.Cursor;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||
import android.text.Html;
|
||||
|
||||
import net.headlezz.notificationlogger.R;
|
||||
import net.headlezz.notificationlogger.logger.BlacklistTable;
|
||||
import net.headlezz.notificationlogger.logger.Logged_notificationTable;
|
||||
|
||||
public class PreferenceFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener {
|
||||
@@ -24,6 +27,7 @@ public class PreferenceFragment extends PreferenceFragmentCompat implements Pref
|
||||
|
||||
interface PreferenceCallbacks {
|
||||
void showAboutScreen();
|
||||
|
||||
void showBlacklistScreen();
|
||||
}
|
||||
|
||||
@@ -33,18 +37,47 @@ public class PreferenceFragment extends PreferenceFragmentCompat implements Pref
|
||||
findPreference(PREF_ABOUT).setOnPreferenceClickListener(this);
|
||||
findPreference(PREF_BLACKLIST).setOnPreferenceClickListener(this);
|
||||
findPreference(PREF_CLEAR_DATABASE).setOnPreferenceClickListener(this);
|
||||
setBlacklistItemCount();
|
||||
}
|
||||
|
||||
private void setBlacklistItemCount() {
|
||||
new AsyncTask<Void, Void, Integer>() {
|
||||
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... params) {
|
||||
Cursor cursor = getContext().getContentResolver().query(
|
||||
BlacklistTable.CONTENT_URI,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
cursor.moveToFirst();
|
||||
return cursor.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer blacklistItemCount) {
|
||||
Preference blacklistPref = findPreference(PREF_BLACKLIST);
|
||||
if (blacklistItemCount > 0)
|
||||
blacklistPref.setSummary(Html.fromHtml(getString(R.string.pref_blacklist_summary_filled, blacklistItemCount)));
|
||||
else
|
||||
blacklistPref.setSummary(getString(R.string.pref_blacklist_summary_empty));
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
String key = preference.getKey();
|
||||
if(key.equals(PREF_ABOUT)) {
|
||||
if (key.equals(PREF_ABOUT)) {
|
||||
mCallbacks.showAboutScreen();
|
||||
return true;
|
||||
} else if(key.equals(PREF_BLACKLIST)) {
|
||||
} else if (key.equals(PREF_BLACKLIST)) {
|
||||
mCallbacks.showBlacklistScreen();
|
||||
return true;
|
||||
} else if(key.equals(PREF_CLEAR_DATABASE))
|
||||
} else if (key.equals(PREF_CLEAR_DATABASE))
|
||||
askClearDatabase();
|
||||
return false;
|
||||
}
|
||||
@@ -77,7 +110,7 @@ public class PreferenceFragment extends PreferenceFragmentCompat implements Pref
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
if(getActivity() != null)
|
||||
if (getActivity() != null)
|
||||
Snackbar.make(getActivity().findViewById(android.R.id.content), R.string.pref_clear_database_snackbar_cleared, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
}.execute();
|
||||
|
||||
Reference in New Issue
Block a user