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 @@ -364,5 +364,11 @@ android:exported="true" android:singleUser="true" android:permission="android.permission.BIND_DREAM_SERVICE" /> <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/layout/notification_guts.xml +10 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,16 @@ android:visibility="gone" /> <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small" android:id="@+id/notification_inspect_filter_notification" android:layout_width="52dp" android:layout_height="match_parent" android:layout_weight="0" android:gravity="center" android:src="@drawable/ic_ringer_mute" android:visibility="gone" /> <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small" android:id="@+id/notification_inspect_item" android:layout_width="52dp" Loading 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; } } } packages/SystemUI/src/com/android/systemui/cm/SpamOpenHelper.java 0 → 100644 +46 −0 Original line number Diff line number Diff line package com.android.systemui.cm; import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable; import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class SpamOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "spam.db"; private static final int VERSION = 4; private static final String CREATE_PACKAGES_TABLE = "create table " + PackageTable.TABLE_NAME + "(" + PackageTable.ID + " INTEGER PRIMARY KEY," + PackageTable.PACKAGE_NAME + " TEXT UNIQUE);"; private static final String CREATE_NOTIFICATIONS_TABLE = "create table " + NotificationTable.TABLE_NAME + "(" + NotificationTable.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + NotificationTable.PACKAGE_ID + " INTEGER," + NotificationTable.MESSAGE_TEXT + " STRING," + NotificationTable.LAST_BLOCKED + " INTEGER," + NotificationTable.NORMALIZED_TEXT + " STRING," + NotificationTable.COUNT + " INTEGER DEFAULT 0);"; private Context mContext; public SpamOpenHelper(Context context) { super(context, DATABASE_NAME, null, VERSION); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_PACKAGES_TABLE); db.execSQL(CREATE_NOTIFICATIONS_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { mContext.deleteDatabase(DATABASE_NAME); onCreate(db); } } 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 @@ -364,5 +364,11 @@ android:exported="true" android:singleUser="true" android:permission="android.permission.BIND_DREAM_SERVICE" /> <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/layout/notification_guts.xml +10 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,16 @@ android:visibility="gone" /> <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small" android:id="@+id/notification_inspect_filter_notification" android:layout_width="52dp" android:layout_height="match_parent" android:layout_weight="0" android:gravity="center" android:src="@drawable/ic_ringer_mute" android:visibility="gone" /> <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small" android:id="@+id/notification_inspect_item" android:layout_width="52dp" Loading
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; } } }
packages/SystemUI/src/com/android/systemui/cm/SpamOpenHelper.java 0 → 100644 +46 −0 Original line number Diff line number Diff line package com.android.systemui.cm; import com.android.internal.util.cm.SpamFilter.SpamContract.NotificationTable; import com.android.internal.util.cm.SpamFilter.SpamContract.PackageTable; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class SpamOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "spam.db"; private static final int VERSION = 4; private static final String CREATE_PACKAGES_TABLE = "create table " + PackageTable.TABLE_NAME + "(" + PackageTable.ID + " INTEGER PRIMARY KEY," + PackageTable.PACKAGE_NAME + " TEXT UNIQUE);"; private static final String CREATE_NOTIFICATIONS_TABLE = "create table " + NotificationTable.TABLE_NAME + "(" + NotificationTable.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + NotificationTable.PACKAGE_ID + " INTEGER," + NotificationTable.MESSAGE_TEXT + " STRING," + NotificationTable.LAST_BLOCKED + " INTEGER," + NotificationTable.NORMALIZED_TEXT + " STRING," + NotificationTable.COUNT + " INTEGER DEFAULT 0);"; private Context mContext; public SpamOpenHelper(Context context) { super(context, DATABASE_NAME, null, VERSION); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_PACKAGES_TABLE); db.execSQL(CREATE_NOTIFICATIONS_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { mContext.deleteDatabase(DATABASE_NAME); onCreate(db); } }