Loading core/java/com/android/internal/util/cm/SpamFilter.java 0 → 100644 +58 −0 Original line number Diff line number Diff line package com.android.internal.util.cm; import android.app.Notification; import android.content.ContentResolver; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; public class SpamFilter { public static final String AUTHORITY = "com.cyanogenmod.spam"; public static final Uri NOTIFICATION_URI = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY) .build(); public static final class SpamContract { public static final class PackageTable { public static final String TABLE_NAME = "packages"; public static final String ID = "_id"; public static final String PACKAGE_NAME = "package_name"; } public static final class NotificationTable { public static final String TABLE_NAME = "notifications"; public static final String ID = "_id"; public static final String PACKAGE_ID = "package_id"; public static final String MESSAGE_TEXT = "message_text"; public static final String COUNT = "count"; public static final String LAST_BLOCKED = "last_blocked"; public static final String NORMALIZED_TEXT = "normalized_text"; } } public static String getNormalizedContent(String msg) { return msg.toLowerCase().replaceAll("[^\\p{L}\\p{Nd}]+", ""); } public static String getNotificationContent(Notification notification) { Bundle extras = notification.extras; String titleExtra = extras.containsKey(Notification.EXTRA_TITLE_BIG) ? Notification.EXTRA_TITLE_BIG : Notification.EXTRA_TITLE; CharSequence notificationTitle = extras.getCharSequence(titleExtra); CharSequence notificationMessage = extras.getCharSequence(Notification.EXTRA_TEXT); if (TextUtils.isEmpty(notificationMessage)) { CharSequence[] inboxLines = extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES); if (inboxLines == null || inboxLines.length == 0) { notificationMessage = ""; } else { notificationMessage = TextUtils.join("\n", inboxLines); } } return notificationTitle + "\n" + notificationMessage; } } packages/SystemUI/AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -280,5 +280,11 @@ <category android:name="android.intent.category.DESK_DOCK" /> </intent-filter> </activity> <provider android:name=".cm.SpamMessageProvider" android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" android:exported="true" android:authorities="com.cyanogenmod.spam" /> </application> </manifest> packages/SystemUI/res/menu/notification_popup_menu.xml +1 −0 Original line number Diff line number Diff line Loading @@ -21,4 +21,5 @@ <item android:id="@+id/notification_inspect_item" android:title="@string/status_bar_notification_inspect_item_title" /> <item android:id="@+id/notification_inspect_item_force_stop" android:title="@string/advanced_dev_option_force_stop" /> <item android:id="@+id/notification_inspect_item_wipe_app" android:title="@string/advanced_dev_option_wipe_app" /> <item android:id="@+id/notification_spam_item" android:title="@string/status_bar_notification_spam_item_title" /> </menu> packages/SystemUI/res/values/cm_strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -125,4 +125,6 @@ <string name="sim_slot" translatable="false">1</string> <string name="sim_slot_2" translatable="false">2</string> <string name="sim_slot_3" translatable="false">3</string> <string name="status_bar_notification_spam_item_title">Block messages like these</string> </resources> packages/SystemUI/src/com/android/systemui/cm/SpamMessageProvider.java 0 → 100644 +196 −0 Original line number Diff line number Diff line package com.android.systemui.cm; import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.text.TextUtils; import com.android.internal.util.cm.SpamFilter; import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable; import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable; public class SpamMessageProvider extends ContentProvider { public static final String AUTHORITY = SpamFilter.AUTHORITY; private static final String UPDATE_COUNT_QUERY = "UPDATE " + NotificationTable.TABLE_NAME + " SET " + NotificationTable.LAST_BLOCKED + "=%d," + NotificationTable.COUNT + "=" + NotificationTable.COUNT + "+1 " + " WHERE " + NotificationTable.ID + "='%s'"; private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int PACKAGES = 0; private static final int MESSAGE = 1; private static final int PACKAGE_ID = 2; private static final int MESSAGE_UPDATE_COUNT = 3; private static final int MESSAGE_FOR_ID = 4; static { sURIMatcher.addURI(AUTHORITY, "packages", PACKAGES); sURIMatcher.addURI(AUTHORITY, "package/id/*", PACKAGE_ID); sURIMatcher.addURI(AUTHORITY, "message", MESSAGE); sURIMatcher.addURI(AUTHORITY, "message/#", MESSAGE_FOR_ID); sURIMatcher.addURI(AUTHORITY, "message/inc_count/#", MESSAGE_UPDATE_COUNT); } private SpamOpenHelper mDbHelper; @Override public boolean onCreate() { mDbHelper = new SpamOpenHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { int match = sURIMatcher.match(uri); switch (match) { case PACKAGE_ID: Cursor idCursor = mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME, new String[]{NotificationTable.ID}, PackageTable.PACKAGE_NAME + "=?", new String[]{uri.getLastPathSegment()}, null, null, null); return idCursor; case PACKAGES: Cursor pkgCursor = mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME, null, null, null, null, null, null); return pkgCursor; case MESSAGE: SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(PackageTable.TABLE_NAME + "," + NotificationTable.TABLE_NAME); String pkgId = PackageTable.TABLE_NAME + "." + PackageTable.ID; String notificationPkgId = NotificationTable.TABLE_NAME + "." + NotificationTable.PACKAGE_ID; qb.appendWhere(pkgId + "=" + notificationPkgId); SQLiteDatabase db = mDbHelper.getReadableDatabase(); Cursor ret = qb.query(db, new String[]{NotificationTable.TABLE_NAME + ".*"}, selection, selectionArgs, null, null, null); ret.moveToFirst(); return ret; case MESSAGE_FOR_ID: qb = new SQLiteQueryBuilder(); qb.setTables(NotificationTable.TABLE_NAME); qb.appendWhere(NotificationTable.PACKAGE_ID + "=" + uri.getLastPathSegment()); db = mDbHelper.getReadableDatabase(); ret = qb.query(db, null, null, null, null, null, null); return ret; default: return null; } } private long getPackageId(String pkg) { long rowId = -1; Cursor idCursor = mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME, new String[]{NotificationTable.ID}, PackageTable.PACKAGE_NAME + "=?", new String[]{pkg}, null, null, null); if (idCursor != null) { if (idCursor.moveToFirst()) { rowId = idCursor.getLong(0); } idCursor.close(); } return rowId; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { if (values == null) { return null; } int match = sURIMatcher.match(uri); switch (match) { case MESSAGE: String msgText = values.getAsString(NotificationTable.MESSAGE_TEXT); String packageName = values.getAsString(PackageTable.PACKAGE_NAME); if (TextUtils.isEmpty(msgText) || TextUtils.isEmpty(packageName)) { return null; } values.clear(); values.put(PackageTable.PACKAGE_NAME, packageName); long packageId = getPackageId(packageName); if (packageId == -1) { packageId = mDbHelper.getWritableDatabase().insert( PackageTable.TABLE_NAME, null, values); } if (packageId != -1) { values.clear(); values.put(NotificationTable.MESSAGE_TEXT, msgText); values.put(NotificationTable.NORMALIZED_TEXT, SpamFilter.getNormalizedContent(msgText)); values.put(NotificationTable.PACKAGE_ID, packageId); values.put(NotificationTable.LAST_BLOCKED, System.currentTimeMillis()); mDbHelper.getReadableDatabase().insert(NotificationTable.TABLE_NAME, null, values); notifyChange(); } return null; default: return null; } } private void notifyChange() { getContext().getContentResolver().notifyChange(SpamFilter.NOTIFICATION_URI, null); } private void removePackageIfNecessary(int packageId) { long numEntries = DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(), NotificationTable.TABLE_NAME, NotificationTable.PACKAGE_ID + "=?", new String[]{String.valueOf(packageId)}); if (numEntries == 0) { mDbHelper.getWritableDatabase().delete(PackageTable.TABLE_NAME, PackageTable.ID + "=?", new String[]{String.valueOf(packageId)}); } } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int match = sURIMatcher.match(uri); switch (match) { case MESSAGE_FOR_ID: int packageId = -1; Cursor idCursor = mDbHelper.getReadableDatabase().query(NotificationTable.TABLE_NAME, new String[]{NotificationTable.PACKAGE_ID}, NotificationTable.ID + "=?", new String[]{uri.getLastPathSegment()}, null, null, null); if (idCursor != null) { if (idCursor.moveToFirst()) { packageId = idCursor.getInt(0); } idCursor.close(); } int result = mDbHelper.getWritableDatabase().delete(NotificationTable.TABLE_NAME, NotificationTable.ID + "=?", new String[]{uri.getLastPathSegment()}); removePackageIfNecessary(packageId); notifyChange(); return result; default: return 0; } } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int match = sURIMatcher.match(uri); switch (match) { case MESSAGE_UPDATE_COUNT: String formattedQuery = String.format(UPDATE_COUNT_QUERY, System.currentTimeMillis(), uri.getLastPathSegment()); mDbHelper.getWritableDatabase().execSQL(formattedQuery); notifyChange(); return 0; default: return 0; } } } Loading
core/java/com/android/internal/util/cm/SpamFilter.java 0 → 100644 +58 −0 Original line number Diff line number Diff line package com.android.internal.util.cm; import android.app.Notification; import android.content.ContentResolver; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; public class SpamFilter { public static final String AUTHORITY = "com.cyanogenmod.spam"; public static final Uri NOTIFICATION_URI = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY) .build(); public static final class SpamContract { public static final class PackageTable { public static final String TABLE_NAME = "packages"; public static final String ID = "_id"; public static final String PACKAGE_NAME = "package_name"; } public static final class NotificationTable { public static final String TABLE_NAME = "notifications"; public static final String ID = "_id"; public static final String PACKAGE_ID = "package_id"; public static final String MESSAGE_TEXT = "message_text"; public static final String COUNT = "count"; public static final String LAST_BLOCKED = "last_blocked"; public static final String NORMALIZED_TEXT = "normalized_text"; } } public static String getNormalizedContent(String msg) { return msg.toLowerCase().replaceAll("[^\\p{L}\\p{Nd}]+", ""); } public static String getNotificationContent(Notification notification) { Bundle extras = notification.extras; String titleExtra = extras.containsKey(Notification.EXTRA_TITLE_BIG) ? Notification.EXTRA_TITLE_BIG : Notification.EXTRA_TITLE; CharSequence notificationTitle = extras.getCharSequence(titleExtra); CharSequence notificationMessage = extras.getCharSequence(Notification.EXTRA_TEXT); if (TextUtils.isEmpty(notificationMessage)) { CharSequence[] inboxLines = extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES); if (inboxLines == null || inboxLines.length == 0) { notificationMessage = ""; } else { notificationMessage = TextUtils.join("\n", inboxLines); } } return notificationTitle + "\n" + notificationMessage; } }
packages/SystemUI/AndroidManifest.xml +6 −0 Original line number Diff line number Diff line Loading @@ -280,5 +280,11 @@ <category android:name="android.intent.category.DESK_DOCK" /> </intent-filter> </activity> <provider android:name=".cm.SpamMessageProvider" android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" android:exported="true" android:authorities="com.cyanogenmod.spam" /> </application> </manifest>
packages/SystemUI/res/menu/notification_popup_menu.xml +1 −0 Original line number Diff line number Diff line Loading @@ -21,4 +21,5 @@ <item android:id="@+id/notification_inspect_item" android:title="@string/status_bar_notification_inspect_item_title" /> <item android:id="@+id/notification_inspect_item_force_stop" android:title="@string/advanced_dev_option_force_stop" /> <item android:id="@+id/notification_inspect_item_wipe_app" android:title="@string/advanced_dev_option_wipe_app" /> <item android:id="@+id/notification_spam_item" android:title="@string/status_bar_notification_spam_item_title" /> </menu>
packages/SystemUI/res/values/cm_strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -125,4 +125,6 @@ <string name="sim_slot" translatable="false">1</string> <string name="sim_slot_2" translatable="false">2</string> <string name="sim_slot_3" translatable="false">3</string> <string name="status_bar_notification_spam_item_title">Block messages like these</string> </resources>
packages/SystemUI/src/com/android/systemui/cm/SpamMessageProvider.java 0 → 100644 +196 −0 Original line number Diff line number Diff line package com.android.systemui.cm; import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.text.TextUtils; import com.android.internal.util.cm.SpamFilter; import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable; import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable; public class SpamMessageProvider extends ContentProvider { public static final String AUTHORITY = SpamFilter.AUTHORITY; private static final String UPDATE_COUNT_QUERY = "UPDATE " + NotificationTable.TABLE_NAME + " SET " + NotificationTable.LAST_BLOCKED + "=%d," + NotificationTable.COUNT + "=" + NotificationTable.COUNT + "+1 " + " WHERE " + NotificationTable.ID + "='%s'"; private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int PACKAGES = 0; private static final int MESSAGE = 1; private static final int PACKAGE_ID = 2; private static final int MESSAGE_UPDATE_COUNT = 3; private static final int MESSAGE_FOR_ID = 4; static { sURIMatcher.addURI(AUTHORITY, "packages", PACKAGES); sURIMatcher.addURI(AUTHORITY, "package/id/*", PACKAGE_ID); sURIMatcher.addURI(AUTHORITY, "message", MESSAGE); sURIMatcher.addURI(AUTHORITY, "message/#", MESSAGE_FOR_ID); sURIMatcher.addURI(AUTHORITY, "message/inc_count/#", MESSAGE_UPDATE_COUNT); } private SpamOpenHelper mDbHelper; @Override public boolean onCreate() { mDbHelper = new SpamOpenHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { int match = sURIMatcher.match(uri); switch (match) { case PACKAGE_ID: Cursor idCursor = mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME, new String[]{NotificationTable.ID}, PackageTable.PACKAGE_NAME + "=?", new String[]{uri.getLastPathSegment()}, null, null, null); return idCursor; case PACKAGES: Cursor pkgCursor = mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME, null, null, null, null, null, null); return pkgCursor; case MESSAGE: SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(PackageTable.TABLE_NAME + "," + NotificationTable.TABLE_NAME); String pkgId = PackageTable.TABLE_NAME + "." + PackageTable.ID; String notificationPkgId = NotificationTable.TABLE_NAME + "." + NotificationTable.PACKAGE_ID; qb.appendWhere(pkgId + "=" + notificationPkgId); SQLiteDatabase db = mDbHelper.getReadableDatabase(); Cursor ret = qb.query(db, new String[]{NotificationTable.TABLE_NAME + ".*"}, selection, selectionArgs, null, null, null); ret.moveToFirst(); return ret; case MESSAGE_FOR_ID: qb = new SQLiteQueryBuilder(); qb.setTables(NotificationTable.TABLE_NAME); qb.appendWhere(NotificationTable.PACKAGE_ID + "=" + uri.getLastPathSegment()); db = mDbHelper.getReadableDatabase(); ret = qb.query(db, null, null, null, null, null, null); return ret; default: return null; } } private long getPackageId(String pkg) { long rowId = -1; Cursor idCursor = mDbHelper.getReadableDatabase().query(PackageTable.TABLE_NAME, new String[]{NotificationTable.ID}, PackageTable.PACKAGE_NAME + "=?", new String[]{pkg}, null, null, null); if (idCursor != null) { if (idCursor.moveToFirst()) { rowId = idCursor.getLong(0); } idCursor.close(); } return rowId; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { if (values == null) { return null; } int match = sURIMatcher.match(uri); switch (match) { case MESSAGE: String msgText = values.getAsString(NotificationTable.MESSAGE_TEXT); String packageName = values.getAsString(PackageTable.PACKAGE_NAME); if (TextUtils.isEmpty(msgText) || TextUtils.isEmpty(packageName)) { return null; } values.clear(); values.put(PackageTable.PACKAGE_NAME, packageName); long packageId = getPackageId(packageName); if (packageId == -1) { packageId = mDbHelper.getWritableDatabase().insert( PackageTable.TABLE_NAME, null, values); } if (packageId != -1) { values.clear(); values.put(NotificationTable.MESSAGE_TEXT, msgText); values.put(NotificationTable.NORMALIZED_TEXT, SpamFilter.getNormalizedContent(msgText)); values.put(NotificationTable.PACKAGE_ID, packageId); values.put(NotificationTable.LAST_BLOCKED, System.currentTimeMillis()); mDbHelper.getReadableDatabase().insert(NotificationTable.TABLE_NAME, null, values); notifyChange(); } return null; default: return null; } } private void notifyChange() { getContext().getContentResolver().notifyChange(SpamFilter.NOTIFICATION_URI, null); } private void removePackageIfNecessary(int packageId) { long numEntries = DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(), NotificationTable.TABLE_NAME, NotificationTable.PACKAGE_ID + "=?", new String[]{String.valueOf(packageId)}); if (numEntries == 0) { mDbHelper.getWritableDatabase().delete(PackageTable.TABLE_NAME, PackageTable.ID + "=?", new String[]{String.valueOf(packageId)}); } } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int match = sURIMatcher.match(uri); switch (match) { case MESSAGE_FOR_ID: int packageId = -1; Cursor idCursor = mDbHelper.getReadableDatabase().query(NotificationTable.TABLE_NAME, new String[]{NotificationTable.PACKAGE_ID}, NotificationTable.ID + "=?", new String[]{uri.getLastPathSegment()}, null, null, null); if (idCursor != null) { if (idCursor.moveToFirst()) { packageId = idCursor.getInt(0); } idCursor.close(); } int result = mDbHelper.getWritableDatabase().delete(NotificationTable.TABLE_NAME, NotificationTable.ID + "=?", new String[]{uri.getLastPathSegment()}); removePackageIfNecessary(packageId); notifyChange(); return result; default: return 0; } } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int match = sURIMatcher.match(uri); switch (match) { case MESSAGE_UPDATE_COUNT: String formattedQuery = String.format(UPDATE_COUNT_QUERY, System.currentTimeMillis(), uri.getLastPathSegment()); mDbHelper.getWritableDatabase().execSQL(formattedQuery); notifyChange(); return 0; default: return 0; } } }