Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b15ac2d7 authored by Danesh Mondegarian's avatar Danesh Mondegarian
Browse files

Filter spam notifications

Change-Id: Ibf2377cd7491c7e0e9e9c9657e9e65eef1876ee3
parent 28a5f8f4
Loading
Loading
Loading
Loading
+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;
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -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>
+1 −0
Original line number Diff line number Diff line
@@ -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>
+2 −0
Original line number Diff line number Diff line
@@ -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>
+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