2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-09-01 06:35:09 +00:00

Rewritten the Notification Filter.

- Now we display every app in the phone.
- We show the app icon next to the name.
- Some apps can now be disabled by default.

Disabled notifications for the default Android messaging app, as SMS
notifications are already handled by the telephony plugin.

BUG: 367930
This commit is contained in:
Albert Vaca
2016-09-20 12:42:56 +02:00
parent ac04f5a610
commit 3b5a7deebe
5 changed files with 164 additions and 147 deletions

View File

@@ -15,10 +15,18 @@
android:paddingBottom="5dp" android:paddingBottom="5dp"
android:id="@+id/tFilter"/> android:id="@+id/tFilter"/>
<ProgressBar
android:layout_marginTop="64dip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="@+id/spinner" />
<ListView <ListView
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:id="@+id/lvFilterApps" android:id="@+id/lvFilterApps"
android:visibility="gone"
/> />
</LinearLayout> </LinearLayout>

View File

@@ -6,4 +6,11 @@ public class StringsHelper {
public static final Charset UTF8 = Charset.forName("UTF-8"); public static final Charset UTF8 = Charset.forName("UTF-8");
public static int compare(String a, String b) {
if (a == b) return 0;
if (a == null) return -1;
if (b == null) return 1;
return a.compareToIgnoreCase(b);
}
} }

View File

@@ -26,26 +26,32 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import java.util.HashSet;
public class AppDatabase { public class AppDatabase {
public static final String KEY_ROW_ID = "id"; static final private HashSet<String> disabledByDefault = new HashSet<>();
public static final String KEY_NAME = "app"; static {
public static final String KEY_PACKAGE_NAME = "packageName"; disabledByDefault.add("com.android.messaging"); //We already have sms notifications in the telephony plugin
public static final String KEY_IS_ENABLED = "isEnabled"; disabledByDefault.add("com.google.android.googlequicksearchbox"); //Google Now notifications re-spawn every few minutes
}
private static final String DATABASE_NAME = "Applications"; static final String KEY_PACKAGE_NAME = "packageName";
private static final String DATABASE_TABLE = "Applications"; static final String KEY_IS_ENABLED = "isEnabled";
private static final int DATABASE_VERSION = 1;
private final Context ourContext; static final String DATABASE_NAME = "Applications";
private SQLiteDatabase ourDatabase; static final String DATABASE_TABLE = "Applications";
private DbHelper ourHelper; static final int DATABASE_VERSION = 2;
final Context ourContext;
SQLiteDatabase ourDatabase;
DbHelper ourHelper;
public AppDatabase(Context c) { public AppDatabase(Context c) {
ourContext = c; ourContext = c;
} }
private static class DbHelper extends SQLiteOpenHelper{ private static class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) { public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -53,73 +59,57 @@ public class AppDatabase {
@Override @Override
public void onCreate(SQLiteDatabase db) { public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + DATABASE_TABLE + "(" + KEY_ROW_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," db.execSQL("CREATE TABLE " + DATABASE_TABLE + "(" + KEY_PACKAGE_NAME + " TEXT PRIMARY KEY NOT NULL, " + KEY_IS_ENABLED + " TEXT NOT NULL); ");
+ KEY_NAME + " TEXT NOT NULL, " + KEY_PACKAGE_NAME + " TEXT NOT NULL, " + KEY_IS_ENABLED + " TEXT NOT NULL); ");
} }
@Override @Override
public void onUpgrade(SQLiteDatabase db, int i, int i2) { public void onUpgrade(SQLiteDatabase db, int i, int i2) {
db.execSQL("DROP TABLE IF EXISTS "+ DATABASE_TABLE); db.execSQL("DROP TABLE IF EXISTS "+ DATABASE_TABLE);
onCreate(db); onCreate(db);
} }
} }
public void open(){ public void open() {
ourHelper = new DbHelper(ourContext); ourHelper = new DbHelper(ourContext);
ourDatabase = ourHelper.getWritableDatabase(); ourDatabase = ourHelper.getWritableDatabase();
} }
public void close() {
public void close(){
ourHelper.close(); ourHelper.close();
} }
public Cursor getAllApplications() public void setEnabled(String packageName, boolean isEnabled) {
{ String[] columns = new String []{KEY_IS_ENABLED};
String[] columns = new String []{KEY_ROW_ID,KEY_NAME,KEY_PACKAGE_NAME,KEY_IS_ENABLED}; Cursor res = ourDatabase.query(DATABASE_TABLE, columns, KEY_PACKAGE_NAME + " =? ",new String[]{packageName},null,null,null);
Cursor res = ourDatabase.query(DATABASE_TABLE,columns,null,null,null,null,KEY_NAME);
return res;
}
public long create(String appName, String packageName, boolean isEnabled) {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
cv.put(KEY_NAME, appName);
cv.put(KEY_PACKAGE_NAME, packageName);
cv.put(KEY_IS_ENABLED, isEnabled?"true":"false"); cv.put(KEY_IS_ENABLED, isEnabled?"true":"false");
return ourDatabase.insert(DATABASE_TABLE, null, cv); if (res.getCount() > 0) {
} cv.put(KEY_PACKAGE_NAME, packageName);
ourDatabase.insert(DATABASE_TABLE, null, cv);
public long update(String packageName, boolean isEnabled) { } else {
ContentValues cvUpdate = new ContentValues(); ourDatabase.update(DATABASE_TABLE, cv, KEY_PACKAGE_NAME + "=?",new String[]{packageName});
cvUpdate.put(KEY_IS_ENABLED, isEnabled?"true":"false"); }
return ourDatabase.update(DATABASE_TABLE,cvUpdate,KEY_PACKAGE_NAME + "=?",new String[]{packageName});
}
public boolean exists(String packageName) {
String[] columns = new String []{KEY_ROW_ID};
Cursor res = ourDatabase.query(DATABASE_TABLE,columns,KEY_PACKAGE_NAME + " =? ",new String[]{packageName},null,null,null);
int count = res.getCount();
res.close(); res.close();
return (count != 0);
} }
public boolean isEnabled(String packageName){ public boolean isEnabled(String packageName) {
String[] columns = new String []{KEY_IS_ENABLED}; String[] columns = new String []{KEY_IS_ENABLED};
Cursor res = ourDatabase.query(DATABASE_TABLE,columns,KEY_PACKAGE_NAME + " =? ",new String[]{packageName},null,null,null); Cursor res = ourDatabase.query(DATABASE_TABLE,columns,KEY_PACKAGE_NAME + " =? ",new String[]{packageName},null,null,null);
boolean result = true; //Apps are enabled by default boolean result;
if (res.getCount() > 0) { if (res.getCount() > 0) {
res.moveToFirst(); res.moveToFirst();
result = (res.getString(res.getColumnIndex(KEY_IS_ENABLED))).equals("true"); result = (res.getString(res.getColumnIndex(KEY_IS_ENABLED))).equals("true");
} else {
result = getDefaultStatus(packageName);
} }
res.close(); res.close();
return result; return result;
} }
public void delete(String packageName){ private boolean getDefaultStatus(String packageName) {
ourDatabase.delete(DATABASE_TABLE,KEY_PACKAGE_NAME + " =? ",new String[]{packageName} ); return !disabledByDefault.contains(packageName);
} }
} }

View File

@@ -22,142 +22,144 @@ package org.kde.kdeconnect.Plugins.NotificationsPlugin;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.Cursor; import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.BaseAdapter;
import android.widget.CheckedTextView;
import android.widget.ListView; import android.widget.ListView;
import org.kde.kdeconnect.BackgroundService; import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Helpers.StringsHelper;
import org.kde.kdeconnect_tp.R; import org.kde.kdeconnect_tp.R;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List; import java.util.List;
public class NotificationFilterActivity extends ActionBarActivity { public class NotificationFilterActivity extends ActionBarActivity {
private AppDatabase appDatabase; AppDatabase appDatabase;
static class AppListInfo {
String pkg;
String name;
Drawable icon;
boolean isEnabled;
}
AppListInfo[] apps;
class AppListAdapter extends BaseAdapter {
@Override
public int getCount() {
return apps.length;
}
@Override
public AppListInfo getItem(int position) {
return apps[position];
}
@Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
LayoutInflater inflater = getLayoutInflater();
view = inflater.inflate(android.R.layout.simple_list_item_multiple_choice, null, true);
}
CheckedTextView checkedTextView = (CheckedTextView)view;
checkedTextView.setText(apps[position].name);
checkedTextView.setCompoundDrawablesWithIntrinsicBounds(apps[position].icon, null, null, null);
checkedTextView.setCompoundDrawablePadding((int)(8*getResources().getDisplayMetrics().density));
return view;
}
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification_filter); setContentView(R.layout.activity_notification_filter);
final ListView listView = (ListView)findViewById(R.id.lvFilterApps); appDatabase = new AppDatabase(NotificationFilterActivity.this);
appDatabase = new AppDatabase(this);
deleteUninstalledApps(); new Thread(new Runnable() {
addNewlyInstalledApps(); @Override
public void run() {
appDatabase.open(); PackageManager packageManager = getPackageManager();
Cursor res = appDatabase.getAllApplications(); List<ApplicationInfo> appList = packageManager.getInstalledApplications(0);
res.moveToFirst(); int count = appList.size();
String[] appName = new String[res.getCount()]; apps = new AppListInfo[count];
final String[] pkgName = new String[res.getCount()]; appDatabase.open();
Boolean[] isFiltered = new Boolean[res.getCount()]; for (int i = 0; i < count; i++) {
ApplicationInfo appInfo = appList.get(i);
apps[i] = new AppListInfo();
apps[i].pkg = appInfo.packageName;
apps[i].name = appInfo.loadLabel(packageManager).toString();
apps[i].icon = resizeIcon(appInfo.loadIcon(packageManager), 48);
apps[i].isEnabled = appDatabase.isEnabled(appInfo.packageName);
}
appDatabase.close();
int i = 0; Arrays.sort(apps, new Comparator<AppListInfo>() {
while(!res.isAfterLast()){ @Override
appName[i] = res.getString(res.getColumnIndex(AppDatabase.KEY_NAME)); public int compare(AppListInfo lhs, AppListInfo rhs) {
pkgName[i] = res.getString(res.getColumnIndex(AppDatabase.KEY_PACKAGE_NAME)); return StringsHelper.compare(lhs.name, rhs.name);
isFiltered[i] = res.getString(res.getColumnIndex(AppDatabase.KEY_IS_ENABLED)).equals("true"); }
res.moveToNext(); });
i++;
}
res.close();
appDatabase.close();
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, runOnUiThread(new Runnable() {
android.R.layout.simple_list_item_multiple_choice, android.R.id.text1, appName); @Override
public void run() {
displayAppList();
}
});
}
}).start();
}
void displayAppList() {
final ListView listView = (ListView) findViewById(R.id.lvFilterApps);
AppListAdapter adapter = new AppListAdapter();
listView.setAdapter(adapter); listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
for (i = 0 ; i < isFiltered.length; i++){
if (isFiltered[i]) {
listView.setItemChecked(i, true);
}
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
boolean checked = listView.isItemChecked(i); boolean checked = listView.isItemChecked(i);
//Log.e("NotificationFilterActivity", pkgName[i] + ":" + checked);
appDatabase.open(); appDatabase.open();
appDatabase.update(pkgName[i], checked); appDatabase.setEnabled(apps[i].pkg, checked);
appDatabase.close(); appDatabase.close();
apps[i].isEnabled = checked;
} }
}); });
} for (int i = 0 ; i < apps.length; i++) {
listView.setItemChecked(i, apps[i].isEnabled);
// Delete apps from database which are uninstalled
private void deleteUninstalledApps(){
Cursor res;
appDatabase.open();
res = appDatabase.getAllApplications();
if (res != null) {
res.moveToFirst();
while (!res.isAfterLast()) {
String packageName = res.getString(res.getColumnIndex(AppDatabase.KEY_PACKAGE_NAME));
if (!isPackageInstalled(packageName)) {
appDatabase.delete(packageName);
}
res.moveToNext();
}
res.close();
}
appDatabase.close();
}
// Adding newly installed apps in database
private void addNewlyInstalledApps() {
List<ApplicationInfo> PackList = getPackageManager().getInstalledApplications(0);
appDatabase.open();
for (int i=0; i < PackList.size(); i++)
{
ApplicationInfo PackInfo = PackList.get(i);
String appName = PackInfo.loadLabel(getPackageManager()).toString();
String packageName = PackInfo.packageName;
if ( (PackInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ) {
if (!appDatabase.exists(packageName)) {
appDatabase.create(appName, packageName, true);
}
//Log.e("App FLAG_UPDATED_SYSTEM_APP: " + Integer.toString(i), appName);
} else if ( (PackInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
//ignore these apps
} else {
if (!appDatabase.exists(packageName)) {
appDatabase.create(appName, packageName, true);
}
//Log.e("App : " + Integer.toString(i), appName);
}
} }
appDatabase.close(); listView.setVisibility(View.VISIBLE);
findViewById(R.id.spinner).setVisibility(View.GONE);
} }
private boolean isPackageInstalled(String packageName){
PackageManager pm = getPackageManager();
try {
pm.getPackageInfo(packageName, PackageManager.GET_META_DATA);
} catch (Exception e) {
return false;
}
return true;
}
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
@@ -170,4 +172,19 @@ public class NotificationFilterActivity extends ActionBarActivity {
BackgroundService.removeGuiInUseCounter(this); BackgroundService.removeGuiInUseCounter(this);
} }
Drawable resizeIcon(Drawable icon, int maxSize) {
Resources res = getResources();
//Convert to display pixels
maxSize = (int)(maxSize*res.getDisplayMetrics().density);
Bitmap bitmap = Bitmap.createBitmap(maxSize, maxSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
icon.draw(canvas);
return new BitmapDrawable(res, bitmap);
}
} }

View File

@@ -170,11 +170,6 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
return; return;
} }
if (packageName.equals("com.google.android.googlequicksearchbox")) {
//HACK: Hide Google Now notifications that keep constantly popping up (and without text because we don't know how to read them properly)
return;
}
NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_NOTIFICATION); NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_NOTIFICATION);
if (packageName.equals("org.kde.kdeconnect_tp")) if (packageName.equals("org.kde.kdeconnect_tp"))