diff --git a/res/layout/popup_notificationsfilter.xml b/res/layout/popup_notificationsfilter.xml
new file mode 100644
--- /dev/null
+++ b/res/layout/popup_notificationsfilter.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/res/layout/privacy_options.xml b/res/layout/privacy_options.xml
new file mode 100644
--- /dev/null
+++ b/res/layout/privacy_options.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -305,4 +305,9 @@
Required by Android since Android 8.0
Since Android 9.0, this notification can only be minimized by long tapping on it
+ Extra options
+ Privacy options
+ Set your privacy options
+ New notification
+
diff --git a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/AppDatabase.java b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/AppDatabase.java
--- a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/AppDatabase.java
+++ b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/AppDatabase.java
@@ -26,6 +26,7 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
import java.util.HashSet;
@@ -41,9 +42,11 @@
private static final int DATABASE_VERSION = 4;
private static final String DATABASE_NAME = "Applications";
- private static final String DATABASE_TABLE = "Applications";
+ private static final String TABLE_ENABLED = "Applications";
+ private static final String TABLE_PRIVACY = "PrivacyOpts";
private static final String KEY_PACKAGE_NAME = "packageName";
private static final String KEY_IS_ENABLED = "isEnabled";
+ private static final String KEY_PRIVACY_OPTIONS = "privacyOptions";
private SQLiteDatabase ourDatabase;
@@ -74,27 +77,33 @@
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + DATABASE_TABLE + "(" + KEY_PACKAGE_NAME + " TEXT PRIMARY KEY NOT NULL, " + KEY_IS_ENABLED + " INTEGER NOT NULL); ");
+ db.execSQL("CREATE TABLE " + TABLE_ENABLED +
+ "(" + KEY_PACKAGE_NAME + " TEXT PRIMARY KEY NOT NULL, " +
+ KEY_IS_ENABLED + " INTEGER NOT NULL ); ");
+ db.execSQL("CREATE TABLE " + TABLE_PRIVACY +
+ "(" + KEY_PACKAGE_NAME + " TEXT PRIMARY KEY NOT NULL, " +
+ KEY_PRIVACY_OPTIONS + " INTEGER NOT NULL); ");
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i2) {
- db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_ENABLED);
onCreate(db);
}
}
void setEnabled(String packageName, boolean isEnabled) {
String[] columns = new String[]{KEY_IS_ENABLED};
- try (Cursor res = ourDatabase.query(DATABASE_TABLE, columns, KEY_PACKAGE_NAME + " =? ", new String[]{packageName}, null, null, null)) {
+ try (Cursor res = ourDatabase.query(TABLE_ENABLED, columns, KEY_PACKAGE_NAME + " =? ", new String[]{packageName}, null, null, null)) {
ContentValues cv = new ContentValues();
cv.put(KEY_IS_ENABLED, isEnabled ? 1 : 0);
if (res.getCount() > 0) {
- ourDatabase.update(DATABASE_TABLE, cv, KEY_PACKAGE_NAME + "=?", new String[]{packageName});
+ ourDatabase.update(TABLE_ENABLED, cv, KEY_PACKAGE_NAME + "=?", new String[]{packageName});
} else {
cv.put(KEY_PACKAGE_NAME, packageName);
- ourDatabase.insert(DATABASE_TABLE, null, cv);
+ long retVal = ourDatabase.insert(TABLE_ENABLED, null, cv);
+ Log.i("AppDatabase", "SetEnabled retval = " + retVal);
}
}
}
@@ -105,12 +114,12 @@
void setAllEnabled(boolean enabled) {
prefs.edit().putBoolean(SETTINGS_KEY_ALL_ENABLED, enabled).apply();
- ourDatabase.execSQL("UPDATE " + DATABASE_TABLE + " SET " + KEY_IS_ENABLED + "=" + (enabled? "1" : "0"));
+ ourDatabase.execSQL("UPDATE " + TABLE_ENABLED + " SET " + KEY_IS_ENABLED + "=" + (enabled? "1" : "0"));
}
boolean isEnabled(String packageName) {
String[] columns = new String[]{KEY_IS_ENABLED};
- try (Cursor res = ourDatabase.query(DATABASE_TABLE, columns, KEY_PACKAGE_NAME + " =? ", new String[]{packageName}, null, null, null)) {
+ try (Cursor res = ourDatabase.query(TABLE_ENABLED, columns, KEY_PACKAGE_NAME + " =? ", new String[]{packageName}, null, null, null)) {
boolean result;
if (res.getCount() > 0) {
res.moveToFirst();
@@ -129,4 +138,55 @@
return getAllEnabled();
}
+ public enum PrivacyOptions {
+ BLOCK_CONTENTS,
+ BLOCK_IMAGES
+ }
+
+ private int getPrivacyOptionsValue(String packageName)
+ {
+ String[] columns = new String[]{KEY_PRIVACY_OPTIONS};
+ try (Cursor res = ourDatabase.query(TABLE_PRIVACY, columns, KEY_PACKAGE_NAME + " =? ", new String[]{packageName}, null, null, null)) {
+ int result;
+ if (res.getCount() > 0) {
+ res.moveToFirst();
+ result = res.getInt(res.getColumnIndex(KEY_PRIVACY_OPTIONS));
+ } else {
+ result = 0;
+ }
+ return result;
+ }
+ }
+
+ private void setPrivacyOptionsValue(String packageName, int value) {
+ String[] columns = new String[]{KEY_PRIVACY_OPTIONS};
+ try (Cursor res = ourDatabase.query(TABLE_PRIVACY, columns, KEY_PACKAGE_NAME + " =? ", new String[]{packageName}, null, null, null)) {
+ ContentValues cv = new ContentValues();
+ cv.put(KEY_PRIVACY_OPTIONS, value);
+ // FIXME inserts data to a database, but getPrivacyOptionsValue() always returns 0
+ if (res.getCount() > 0) {
+ ourDatabase.update(TABLE_PRIVACY, cv, KEY_PACKAGE_NAME + "=?", new String[]{packageName});
+ } else {
+ cv.put(KEY_PACKAGE_NAME, packageName);
+ long retVal = ourDatabase.insert(TABLE_PRIVACY, null, cv);
+ Log.i("AppDatabase", "SetPrivacyOptions retval = " + retVal);
+ }
+ }
+ }
+
+ public void setPrivacy(String packageName, PrivacyOptions option, boolean isBlocked) {
+ int curBit = option.ordinal();
+ int value = getPrivacyOptionsValue(packageName);
+ value |= (1 << curBit);
+ value ^= isBlocked ? 0 : (1 << curBit);
+ setPrivacyOptionsValue(packageName, value);
+ }
+
+ public boolean getPrivacy(String packageName, PrivacyOptions option) {
+ int curBit = option.ordinal();
+ int value = getPrivacyOptionsValue(packageName);
+ int bit = value & (1 << curBit);
+ return bit != 0;
+ // We still use getPrivacy() in NotificationsPlugin.java, because this function anyways always returns false, so it doesn't block anything
+ }
}
diff --git a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java
--- a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java
@@ -20,6 +20,8 @@
package org.kde.kdeconnect.Plugins.NotificationsPlugin;
+import android.app.AlertDialog;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -32,11 +34,15 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
+import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.ListView;
import org.kde.kdeconnect.BackgroundService;
+import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.StringsHelper;
import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
@@ -132,6 +138,7 @@
AppListAdapter adapter = new AppListAdapter();
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+ listView.setLongClickable(true);
listView.setOnItemClickListener((adapterView, view, i, l) -> {
if (i == 0) {
@@ -147,6 +154,59 @@
apps[i - 1].isEnabled = checked;
}
});
+ listView.setOnItemLongClickListener((adapterView, view, i, l) -> {
+ if(i == 0)
+ return true;
+ Context context = this;
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ View mView = getLayoutInflater().inflate(R.layout.popup_notificationsfilter, null);
+ builder.setMessage(context.getResources().getString(R.string.extra_options));
+
+ ListView lv = mView.findViewById(R.id.extra_options_list);
+ final String[] options = new String[] {
+ context.getResources().getString(R.string.privacy_options)
+ };
+ ArrayAdapter extra_options_adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_list_item_1, options);
+ lv.setAdapter(extra_options_adapter);
+ builder.setView(mView);
+
+ AlertDialog ad = builder.create();
+
+ lv.setOnItemClickListener((new_adapterView, new_view, new_i, new_l) -> {
+ switch (new_i){
+ case 0:
+ AlertDialog.Builder myBuilder = new AlertDialog.Builder(context);
+ String packageName = apps[i - 1].pkg;
+ boolean testIsEnabled = appDatabase.isEnabled(packageName);
+
+ View myView = getLayoutInflater().inflate(R.layout.privacy_options, null);
+ CheckBox checkbox_contents = myView.findViewById(R.id.checkbox_contents);
+ checkbox_contents.setChecked(appDatabase.getPrivacy(packageName, AppDatabase.PrivacyOptions.BLOCK_CONTENTS));
+ CheckBox checkbox_images = myView.findViewById(R.id.checkbox_images);
+ checkbox_images.setChecked(appDatabase.getPrivacy(packageName, AppDatabase.PrivacyOptions.BLOCK_IMAGES));
+
+ myBuilder.setView(myView);
+ myBuilder.setTitle(context.getResources().getString(R.string.privacy_options));
+ myBuilder.setPositiveButton(context.getResources().getString(R.string.ok), (dialog, id) -> dialog.dismiss());
+ myBuilder.setMessage(context.getResources().getString(R.string.set_privacy_options));
+
+ checkbox_contents.setOnCheckedChangeListener((compoundButton, b) ->
+ appDatabase.setPrivacy(packageName, AppDatabase.PrivacyOptions.BLOCK_CONTENTS,
+ compoundButton.isChecked()));
+ checkbox_images.setOnCheckedChangeListener((compoundButton, b) ->
+ appDatabase.setPrivacy(packageName, AppDatabase.PrivacyOptions.BLOCK_IMAGES,
+ compoundButton.isChecked()));
+
+ ad.cancel();
+ myBuilder.create().show();
+ break;
+ }
+ });
+
+ ad.show();
+ return true;
+ });
listView.setItemChecked(0, appDatabase.getAllEnabled()); //"Select all" button
for (int i = 0; i < apps.length; i++) {
diff --git a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java
--- a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java
+++ b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationsPlugin.java
@@ -15,7 +15,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * along with this program. If not, see .
*/
package org.kde.kdeconnect.Plugins.NotificationsPlugin;
@@ -225,7 +225,8 @@
}
}
- if (appIcon != null) {
+ if (appIcon != null && !appDatabase.getPrivacy(packageName, AppDatabase.PrivacyOptions.BLOCK_IMAGES)) {
+
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
appIcon.compress(Bitmap.CompressFormat.PNG, 90, outStream);
byte[] bitmapData = outStream.toByteArray();
@@ -244,18 +245,28 @@
currentNotifications.add(key);
}
- RepliableNotification rn = extractRepliableNotification(statusBarNotification);
- if (rn.pendingIntent != null) {
- np.set("requestReplyId", rn.id);
- pendingIntents.put(rn.id, rn);
+ boolean blockContents = appDatabase.getPrivacy(packageName, AppDatabase.PrivacyOptions.BLOCK_CONTENTS);
+
+ if (!blockContents) {
+ RepliableNotification rn = extractRepliableNotification(statusBarNotification);
+ if (rn.pendingIntent != null) {
+ np.set("requestReplyId", rn.id);
+ pendingIntents.put(rn.id, rn);
+ }
}
np.set("id", key);
- np.set("appName", appName == null ? packageName : appName);
np.set("isClearable", statusBarNotification.isClearable());
- np.set("ticker", getTickerText(notification));
- np.set("title", getNotificationTitle(notification));
- np.set("text", getNotificationText(notification));
+ np.set("appName", appName == null ? packageName : appName);
+ if(blockContents) {
+ np.set("ticker", "");
+ np.set("title", "");
+ //np.set("text", "");
+ } else {
+ np.set("ticker", getTickerText(notification));
+ np.set("title", getNotificationTitle(notification));
+ np.set("text", getNotificationText(notification));
+ }
np.set("time", Long.toString(statusBarNotification.getPostTime()));
device.sendPacket(np);