From b2f985aa03d464e4881a54190a890251e722480d Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 20 Mar 2018 13:43:11 +0100 Subject: [PATCH] New Notification engine --- .../activities/EntryActivity.java | 26 ++- .../NotificationCopyingService.java | 135 +++---------- .../notifications/NotificationField.java | 177 ++++++++++++++++++ 3 files changed, 229 insertions(+), 109 deletions(-) create mode 100644 app/src/main/java/com/keepassdroid/notifications/NotificationField.java diff --git a/app/src/main/java/com/keepassdroid/activities/EntryActivity.java b/app/src/main/java/com/keepassdroid/activities/EntryActivity.java index 2060714e2..47cae9267 100644 --- a/app/src/main/java/com/keepassdroid/activities/EntryActivity.java +++ b/app/src/main/java/com/keepassdroid/activities/EntryActivity.java @@ -39,8 +39,9 @@ import com.keepassdroid.compat.ActivityCompat; import com.keepassdroid.database.Database; import com.keepassdroid.database.PwDatabase; import com.keepassdroid.database.PwEntry; -import com.keepassdroid.password.PasswordActivity; import com.keepassdroid.notifications.NotificationCopyingService; +import com.keepassdroid.notifications.NotificationField; +import com.keepassdroid.password.PasswordActivity; import com.keepassdroid.settings.PreferencesUtil; import com.keepassdroid.timeout.ClipboardHelper; import com.keepassdroid.utils.EmptyUtils; @@ -50,6 +51,7 @@ import com.keepassdroid.utils.Util; import com.keepassdroid.view.EntryContentsView; import com.kunzisoft.keepass.R; +import java.util.ArrayList; import java.util.Date; import java.util.Map; import java.util.UUID; @@ -146,12 +148,26 @@ public class EntryActivity extends LockingHideActivity { // username already copied, waiting for user's action before copy password. Intent intent = new Intent(this, NotificationCopyingService.class); intent.setAction(NotificationCopyingService.ACTION_NEW_NOTIFICATION); - intent.putExtra(NotificationCopyingService.EXTRA_PASSWORD, mEntry.getPassword()); - if (mEntry.getUsername().length() > 0) { - intent.putExtra(NotificationCopyingService.EXTRA_USERNAME, mEntry.getUsername()); - } if (mEntry.getTitle() != null) intent.putExtra(NotificationCopyingService.EXTRA_ENTRY_TITLE, mEntry.getTitle()); + // Construct notification fields + ArrayList notificationFields = new ArrayList<>(); + // Add username if exists to notifications + if (mEntry.getUsername().length() > 0) + notificationFields.add( + new NotificationField( + NotificationField.NotificationFieldId.USERNAME, + mEntry.getUsername(), + getResources())); + // Add password to notifications + notificationFields.add( + new NotificationField( + NotificationField.NotificationFieldId.PASSWORD, + mEntry.getPassword(), + getResources())); + // Add notifications + intent.putParcelableArrayListExtra(NotificationCopyingService.EXTRA_FIELDS, notificationFields); + startService(intent); } } diff --git a/app/src/main/java/com/keepassdroid/notifications/NotificationCopyingService.java b/app/src/main/java/com/keepassdroid/notifications/NotificationCopyingService.java index 9c5f1724c..210e65599 100755 --- a/app/src/main/java/com/keepassdroid/notifications/NotificationCopyingService.java +++ b/app/src/main/java/com/keepassdroid/notifications/NotificationCopyingService.java @@ -30,12 +30,7 @@ public class NotificationCopyingService extends Service { public static final String ACTION_NEW_NOTIFICATION = "ACTION_NEW_NOTIFICATION"; public static final String EXTRA_ENTRY_TITLE = "EXTRA_ENTRY_TITLE"; - public static final String EXTRA_USERNAME = "EXTRA_USERNAME"; - public static final String EXTRA_PASSWORD = "EXTRA_PASSWORD"; - - public static final String ACTION_COPY_USERNAME = "ACTION_COPY_USERNAME"; - public static final String ACTION_COPY_PASSWORD = "ACTION_COPY_PASSWORD"; - + public static final String EXTRA_FIELDS = "EXTRA_FIELDS"; public static final String ACTION_CLEAN_CLIPBOARD = "ACTION_CLEAN_CLIPBOARD"; private NotificationManager notificationManager; @@ -81,21 +76,8 @@ public class NotificationCopyingService extends Service { } else if (ACTION_NEW_NOTIFICATION.equals(intent.getAction())) { String title = intent.getStringExtra(EXTRA_ENTRY_TITLE); - String password = intent.getStringExtra(EXTRA_PASSWORD); - if (password == null) { - Log.e(TAG, "password is null"); - return START_NOT_STICKY; - } newNotification(title, constructListOfField(intent)); - } else if (ACTION_COPY_USERNAME.equals(intent.getAction())) { - String fieldValueToCopy = intent.getStringExtra(EXTRA_USERNAME); - copyField(new Field(EXTRA_USERNAME, fieldValueToCopy), constructListOfField(intent)); - - } else if (ACTION_COPY_PASSWORD.equals(intent.getAction())) { - String fieldValueToCopy = intent.getStringExtra(EXTRA_PASSWORD); - copyField(new Field(EXTRA_PASSWORD, fieldValueToCopy), constructListOfField(intent)); - } else if (ACTION_CLEAN_CLIPBOARD.equals(intent.getAction())) { stopTask(countingDownTask); try { @@ -103,66 +85,43 @@ public class NotificationCopyingService extends Service { } catch (SamsungClipboardException e) { Log.e(TAG, "Clipboard can't be cleaned", e); } + } else { - Log.w(TAG, "unknown action"); + for (String actionKey : NotificationField.getAllActionKeys()) { + if (actionKey.equals(intent.getAction())) { + NotificationField fieldToCopy = intent.getParcelableExtra( + NotificationField.getExtraKeyLinkToActionKey(actionKey)); + ArrayList nextFields = constructListOfField(intent); + // Remove the current field from the next fields + if (nextFields.contains(fieldToCopy)) + nextFields.remove(fieldToCopy); + copyField(fieldToCopy, nextFields); + } + } } return START_NOT_STICKY; } - private List constructListOfField(Intent intent) { - List fieldList = new ArrayList<>(); + private ArrayList constructListOfField(Intent intent) { + ArrayList fieldList = new ArrayList<>(); if (intent != null && intent.getExtras() != null) { - if (intent.getExtras().containsKey(EXTRA_USERNAME)) - fieldList.add(new Field( - EXTRA_USERNAME, - intent.getStringExtra(EXTRA_USERNAME))); - if (intent.getExtras().containsKey(EXTRA_PASSWORD)) - fieldList.add(new Field( - EXTRA_PASSWORD, - intent.getStringExtra(EXTRA_PASSWORD))); + if (intent.getExtras().containsKey(EXTRA_FIELDS)) + fieldList = intent.getParcelableArrayListExtra(EXTRA_FIELDS); } return fieldList; } - private String getLabelFromExtra(String extra) { - switch (extra) { - case EXTRA_USERNAME: - return getString(R.string.entry_user_name); - case EXTRA_PASSWORD: - return getString(R.string.entry_password); - default: - return ""; - } - } - - private String getCopyTextFromExtra(String extra) { - switch (extra) { - case EXTRA_USERNAME: - return getString(R.string.copy_username); - case EXTRA_PASSWORD: - return getString(R.string.copy_password); - default: - return ""; - } - } - - private PendingIntent getCopyPendingIntent(Field field, List fieldsToAdd) { + private PendingIntent getCopyPendingIntent(NotificationField fieldToCopy, ArrayList fieldsToAdd) { Intent copyIntent = new Intent(this, NotificationCopyingService.class); - switch (field.extra) { - case EXTRA_USERNAME: - copyIntent.setAction(ACTION_COPY_USERNAME); - break; - case EXTRA_PASSWORD: - copyIntent.setAction(ACTION_COPY_PASSWORD); - } - for (Field fieldToAdd : fieldsToAdd) { - copyIntent.putExtra(fieldToAdd.extra, fieldToAdd.value); - } + copyIntent.setAction(fieldToCopy.getActionKey()); + copyIntent.putExtra(fieldToCopy.getExtraKey(), fieldToCopy); + copyIntent.putParcelableArrayListExtra(EXTRA_FIELDS, fieldsToAdd); + return PendingIntent.getService( this, 0, copyIntent, PendingIntent.FLAG_UPDATE_CURRENT); } - private void newNotification(@Nullable String title, List fieldsToAdd) { + private void newNotification(@Nullable String title, ArrayList fieldsToAdd) { stopTask(countingDownTask); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID_COPYING) @@ -173,15 +132,15 @@ public class NotificationCopyingService extends Service { builder.setVisibility(Notification.VISIBILITY_SECRET); if (fieldsToAdd.size() > 0) { - Field field = fieldsToAdd.get(fieldsToAdd.size() - 1); + NotificationField field = fieldsToAdd.get(0); builder.setContentText(field.copyText); builder.setContentIntent(getCopyPendingIntent(field, fieldsToAdd)); - // Add extra actions without password - List fieldsWithoutPassword = new ArrayList<>(fieldsToAdd); - fieldsWithoutPassword.remove(field); + // Add extra actions without 1st field + List fieldsWithoutFirstField = new ArrayList<>(fieldsToAdd); + fieldsWithoutFirstField.remove(field); // Add extra actions - for (Field fieldToAdd : fieldsWithoutPassword) { + for (NotificationField fieldToAdd : fieldsWithoutFirstField) { builder.addAction(R.drawable.ic_key_white_24dp, fieldToAdd.label, getCopyPendingIntent(fieldToAdd, fieldsToAdd)); } @@ -204,7 +163,7 @@ public class NotificationCopyingService extends Service { cleanNotificationTimer.start(); } - private void copyField(Field fieldToCopy, List nextFields) { + private void copyField(NotificationField fieldToCopy, ArrayList nextFields) { stopTask(countingDownTask); stopTask(cleanNotificationTimer); @@ -215,12 +174,9 @@ public class NotificationCopyingService extends Service { .setSmallIcon(R.drawable.ic_key_white_24dp) .setContentTitle(fieldToCopy.label); - // Remove the current field from the next fields - if (nextFields.contains(fieldToCopy)) - nextFields.remove(fieldToCopy); // New action with next field if click if (nextFields.size() > 0) { - Field nextField = nextFields.get(0); + NotificationField nextField = nextFields.get(0); builder.setContentText(nextField.copyText); builder.setContentIntent(getCopyPendingIntent(nextField, nextFields)); // Else tell to swipe for a clean @@ -260,7 +216,7 @@ public class NotificationCopyingService extends Service { }); countingDownTask.start(); - } catch (SamsungClipboardException e) { + } catch (Exception e) { Log.e(TAG, "Clipboard can't be populate", e); } } @@ -270,33 +226,4 @@ public class NotificationCopyingService extends Service { task.interrupt(); } - /** - * Utility class to manage fields in Notifications - */ - private class Field { - String extra; - String label; - String copyText; - String value; - - Field(String extra, String value) { - this.extra = extra; - this.label = getLabelFromExtra(extra); - this.copyText = getCopyTextFromExtra(extra); - this.value = value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Field field = (Field) o; - return extra.equals(field.extra); - } - - @Override - public int hashCode() { - return extra.hashCode(); - } - } } diff --git a/app/src/main/java/com/keepassdroid/notifications/NotificationField.java b/app/src/main/java/com/keepassdroid/notifications/NotificationField.java new file mode 100644 index 000000000..4add0d45d --- /dev/null +++ b/app/src/main/java/com/keepassdroid/notifications/NotificationField.java @@ -0,0 +1,177 @@ +/* + * + * Copyright 2017 Jeremy Jamet / Kunzisoft. + * + * This file is part of KeePass DX. + * + * KeePass DX is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * KeePass DX is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KeePass DX. If not, see . + * + */ + +package com.keepassdroid.notifications; + +import android.content.res.Resources; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import com.kunzisoft.keepass.R; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nullable; + +/** + * Utility class to manage fields in Notifications + */ +public class NotificationField implements Parcelable { + + private static final String TAG = NotificationField.class.getName(); + + private NotificationFieldId id; + String value; + String label; + String copyText; + + public NotificationField(NotificationFieldId id, String value, Resources resources) { + this.id = id; + this.value = value; + this.label = getLabel(resources); + this.copyText = getCopyText(resources); + } + + protected NotificationField(Parcel in) { + id = NotificationFieldId.values()[in.readInt()]; + value = in.readString(); + label = in.readString(); + copyText = in.readString(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(id.ordinal()); + dest.writeString(value); + dest.writeString(label); + dest.writeString(copyText); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public NotificationField createFromParcel(Parcel in) { + return new NotificationField(in); + } + + @Override + public NotificationField[] newArray(int size) { + return new NotificationField[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NotificationField field = (NotificationField) o; + return id.equals(field.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + public enum NotificationFieldId { + USERNAME, PASSWORD, FIELD_A, FIELD_B, FIELD_C; + } + + private static final String ACTION_COPY_PREFIX = "ACTION_COPY_"; + private static final String EXTRA_KEY_PREFIX = "EXTRA_"; + + /** + * Return EXTRA_KEY link to ACTION_KEY, or null if ACTION_KEY is unknown + */ + public static @Nullable String getExtraKeyLinkToActionKey(String actionKey) { + try { + if (actionKey.startsWith(ACTION_COPY_PREFIX)) { + String idName = actionKey.substring(ACTION_COPY_PREFIX.length(), actionKey.length()); + return getExtraKey(NotificationFieldId.valueOf(idName)); + } + } catch (Exception e) { + Log.e(TAG, "Can't get Extra Key from Action Key", e); + } + return null; + } + + private static String getActionKey(NotificationFieldId id) { + return ACTION_COPY_PREFIX + id.name(); + } + + public String getActionKey() { + return getActionKey(id); + } + + private static String getExtraKey(NotificationFieldId id) { + return EXTRA_KEY_PREFIX + id.name(); + } + + public String getExtraKey() { + return getExtraKey(id); + } + + public static List getAllActionKeys() { + List actionKeys = new ArrayList<>(); + for (NotificationFieldId id : NotificationFieldId.values()) { + actionKeys.add(getActionKey(id)); + } + return actionKeys; + } + + public static List getAllExtraKeys() { + List extraKeys = new ArrayList<>(); + for (NotificationFieldId id : NotificationFieldId.values()) { + extraKeys.add(getExtraKey(id)); + } + return extraKeys; + } + + private String getLabel(Resources resources) { + switch (id) { + case USERNAME: + return resources.getString(R.string.entry_user_name); + case PASSWORD: + return resources.getString(R.string.entry_password); + // TODO default + default: + return ""; + } + } + + private String getCopyText(Resources resources) { + switch (id) { + case USERNAME: + return resources.getString(R.string.copy_username); + case PASSWORD: + return resources.getString(R.string.copy_password); + // TODO default + default: + return ""; + } + } +}