Loading core/java/android/app/Notification.java +20 −0 Original line number Diff line number Diff line Loading @@ -983,6 +983,17 @@ public class Notification implements Parcelable */ public static final String EXTRA_SHOW_REMOTE_INPUT_SPINNER = "android.remoteInputSpinner"; /** * {@link #extras} key: boolean as supplied to * {@link Builder#setHideSmartReplies(boolean)}. * * If set to true, then any smart reply buttons will be hidden. * * @see Builder#setHideSmartReplies(boolean) * @hide */ public static final String EXTRA_HIDE_SMART_REPLIES = "android.hideSmartReplies"; /** * {@link #extras} key: this is a small piece of additional text as supplied to * {@link Builder#setContentInfo(CharSequence)}. Loading Loading @@ -3594,6 +3605,15 @@ public class Notification implements Parcelable return this; } /** * Sets whether smart reply buttons should be hidden. * @hide */ public Builder setHideSmartReplies(boolean hideSmartReplies) { mN.extras.putBoolean(EXTRA_HIDE_SMART_REPLIES, hideSmartReplies); return this; } /** * Sets the number of items this notification represents. May be displayed as a badge count * for Launchers that support badging. Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +7 −0 Original line number Diff line number Diff line Loading @@ -1384,6 +1384,13 @@ public class NotificationContentView extends FrameLayout { smartReplyContainer.setVisibility(View.GONE); return null; } // If we are keeping the notification around while sending we don't want to add the buttons. boolean hideSmartReplies = entry.notification.getNotification() .extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false); if (hideSmartReplies) { smartReplyContainer.setVisibility(View.GONE); return null; } SmartReplyView smartReplyView = null; if (smartReplyContainer.getChildCount() == 0) { smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer); Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java +82 −11 Original line number Diff line number Diff line Loading @@ -113,6 +113,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. Dependency.get(ForegroundServiceController.class); protected final NotificationListener mNotificationListener = Dependency.get(NotificationListener.class); private final SmartReplyController mSmartReplyController = Dependency.get(SmartReplyController.class); protected IStatusBarService mBarService; protected NotificationPresenter mPresenter; Loading @@ -127,6 +129,13 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. protected boolean mDisableNotificationAlerts; protected NotificationListContainer mListContainer; private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; /** * Notifications with keys in this set are not actually around anymore. We kept them around * when they were canceled in response to a remote input interaction. This allows us to show * what you replied and allows you to continue typing into it. */ private final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>(); private final class NotificationClicker implements View.OnClickListener { Loading Loading @@ -220,6 +229,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } pw.print(" mUseHeadsUp="); pw.println(mUseHeadsUp); pw.print(" mKeysKeptForRemoteInput: "); pw.println(mKeysKeptForRemoteInput); } public NotificationEntryManager(Context context) { Loading Loading @@ -374,6 +385,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count, true); NotificationData.Entry entry = mNotificationData.get(n.getKey()); if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(n.getKey())) { mKeysKeptForRemoteInput.remove(n.getKey()); } mRemoteInputManager.onPerformRemoveNotification(n, entry); final String pkg = n.getPackageName(); final String tag = n.getTag(); Loading Loading @@ -491,10 +508,35 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } if (updated) { Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key); mRemoteInputManager.getKeysKeptForRemoteInput().add(entry.key); addKeyKeptForRemoteInput(entry.key); return; } } if (FORCE_REMOTE_INPUT_HISTORY && shouldKeepForSmartReply(entry) && entry.row != null && !entry.row.isDismissed()) { // Turn off the spinner and hide buttons when an app cancels the notification. StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry); boolean updated = false; try { updateNotificationInternal(newSbn, null); updated = true; } catch (InflationException e) { // Ignore just don't keep the notification around. } // Treat the reply as longer sending. mSmartReplyController.stopSending(entry); if (updated) { Log.w(TAG, "Keeping notification around after sending smart reply " + entry.key); addKeyKeptForRemoteInput(entry.key); return; } } // Actually removing notification so smart reply controller can forget about it. mSmartReplyController.stopSending(entry); if (deferRemoval) { mLatestRankingMap = ranking; mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key)); Loading Loading @@ -536,6 +578,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. Notification.Builder b = Notification.Builder .recoverBuilder(mContext, sbn.getNotification().clone()); if (remoteInputText != null) { CharSequence[] oldHistory = sbn.getNotification().extras .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); CharSequence[] newHistory; Loading @@ -547,7 +590,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } newHistory[0] = String.valueOf(remoteInputText); b.setRemoteInputHistory(newHistory); } b.setShowRemoteInputSpinner(showSpinner); b.setHideSmartReplies(true); Notification newNotification = b.build(); Loading @@ -563,6 +608,17 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. return newSbn; } @VisibleForTesting StatusBarNotification rebuildNotificationForCanceledSmartReplies( NotificationData.Entry entry) { return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */, false /* showSpinner */); } private boolean shouldKeepForSmartReply(NotificationData.Entry entry) { return entry != null && mSmartReplyController.isSendingSmartReply(entry.key); } private boolean shouldKeepForRemoteInput(NotificationData.Entry entry) { if (entry == null) { return false; Loading Loading @@ -792,6 +848,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } mHeadsUpEntriesToRemoveOnSwitch.remove(entry); mRemoteInputManager.onUpdateNotification(entry); mSmartReplyController.stopSending(entry); if (key.equals(mGutsManager.getKeyToRemoveOnGutsClosed())) { mGutsManager.setKeyToRemoveOnGutsClosed(null); Loading Loading @@ -955,6 +1012,20 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. return mHeadsUpManager.isHeadsUp(key); } public boolean isNotificationKeptForRemoteInput(String key) { return mKeysKeptForRemoteInput.contains(key); } public void removeKeyKeptForRemoteInput(String key) { mKeysKeptForRemoteInput.remove(key); } public void addKeyKeptForRemoteInput(String key) { if (FORCE_REMOTE_INPUT_HISTORY) { mKeysKeptForRemoteInput.add(key); } } /** * Callback for NotificationEntryManager. */ Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java +1 −1 Original line number Diff line number Diff line Loading @@ -75,7 +75,7 @@ public class NotificationListener extends NotificationListenerWithPlugins { mPresenter.getHandler().post(() -> { processForRemoteInput(sbn.getNotification(), mContext); String key = sbn.getKey(); mRemoteInputManager.getKeysKeptForRemoteInput().remove(key); mEntryManager.removeKeyKeptForRemoteInput(key); boolean isUpdate = mEntryManager.getNotificationData().get(key) != null; // In case we don't allow child notifications, we ignore children of Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +2 −17 Original line number Diff line number Diff line Loading @@ -77,12 +77,6 @@ public class NotificationRemoteInputManager implements Dumpable { protected final NotificationLockscreenUserManager mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class); /** * Notifications with keys in this set are not actually around anymore. We kept them around * when they were canceled in response to a remote input interaction. This allows us to show * what you replied and allows you to continue typing into it. */ protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>(); protected final Context mContext; private final UserManager mUserManager; Loading Loading @@ -290,7 +284,8 @@ public class NotificationRemoteInputManager implements Dumpable { mRemoteInputController.addCallback(new RemoteInputController.Callback() { @Override public void onRemoteInputSent(NotificationData.Entry entry) { if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) { if (FORCE_REMOTE_INPUT_HISTORY && mEntryManager.isNotificationKeptForRemoteInput(entry.key)) { mEntryManager.removeNotification(entry.key, null); } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) { // We're currently holding onto this notification, but from the apps point of Loading Loading @@ -340,10 +335,6 @@ public class NotificationRemoteInputManager implements Dumpable { if (mRemoteInputController.isRemoteInputActive(entry)) { mRemoteInputController.removeRemoteInput(entry, null); } if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(n.getKey())) { mKeysKeptForRemoteInput.remove(n.getKey()); } } public void removeRemoteInputEntriesKeptUntilCollapsed() { Loading @@ -368,8 +359,6 @@ public class NotificationRemoteInputManager implements Dumpable { pw.println("NotificationRemoteInputManager state:"); pw.print(" mRemoteInputEntriesToRemoveOnCollapse: "); pw.println(mRemoteInputEntriesToRemoveOnCollapse); pw.print(" mKeysKeptForRemoteInput: "); pw.println(mKeysKeptForRemoteInput); } public void bindRow(ExpandableNotificationRow row) { Loading @@ -377,10 +366,6 @@ public class NotificationRemoteInputManager implements Dumpable { row.setRemoteViewClickHandler(mOnClickHandler); } public Set<String> getKeysKeptForRemoteInput() { return mKeysKeptForRemoteInput; } @VisibleForTesting public Set<NotificationData.Entry> getRemoteInputEntriesToRemoveOnCollapse() { return mRemoteInputEntriesToRemoveOnCollapse; Loading Loading
core/java/android/app/Notification.java +20 −0 Original line number Diff line number Diff line Loading @@ -983,6 +983,17 @@ public class Notification implements Parcelable */ public static final String EXTRA_SHOW_REMOTE_INPUT_SPINNER = "android.remoteInputSpinner"; /** * {@link #extras} key: boolean as supplied to * {@link Builder#setHideSmartReplies(boolean)}. * * If set to true, then any smart reply buttons will be hidden. * * @see Builder#setHideSmartReplies(boolean) * @hide */ public static final String EXTRA_HIDE_SMART_REPLIES = "android.hideSmartReplies"; /** * {@link #extras} key: this is a small piece of additional text as supplied to * {@link Builder#setContentInfo(CharSequence)}. Loading Loading @@ -3594,6 +3605,15 @@ public class Notification implements Parcelable return this; } /** * Sets whether smart reply buttons should be hidden. * @hide */ public Builder setHideSmartReplies(boolean hideSmartReplies) { mN.extras.putBoolean(EXTRA_HIDE_SMART_REPLIES, hideSmartReplies); return this; } /** * Sets the number of items this notification represents. May be displayed as a badge count * for Launchers that support badging. Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +7 −0 Original line number Diff line number Diff line Loading @@ -1384,6 +1384,13 @@ public class NotificationContentView extends FrameLayout { smartReplyContainer.setVisibility(View.GONE); return null; } // If we are keeping the notification around while sending we don't want to add the buttons. boolean hideSmartReplies = entry.notification.getNotification() .extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false); if (hideSmartReplies) { smartReplyContainer.setVisibility(View.GONE); return null; } SmartReplyView smartReplyView = null; if (smartReplyContainer.getChildCount() == 0) { smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer); Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java +82 −11 Original line number Diff line number Diff line Loading @@ -113,6 +113,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. Dependency.get(ForegroundServiceController.class); protected final NotificationListener mNotificationListener = Dependency.get(NotificationListener.class); private final SmartReplyController mSmartReplyController = Dependency.get(SmartReplyController.class); protected IStatusBarService mBarService; protected NotificationPresenter mPresenter; Loading @@ -127,6 +129,13 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. protected boolean mDisableNotificationAlerts; protected NotificationListContainer mListContainer; private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; /** * Notifications with keys in this set are not actually around anymore. We kept them around * when they were canceled in response to a remote input interaction. This allows us to show * what you replied and allows you to continue typing into it. */ private final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>(); private final class NotificationClicker implements View.OnClickListener { Loading Loading @@ -220,6 +229,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } pw.print(" mUseHeadsUp="); pw.println(mUseHeadsUp); pw.print(" mKeysKeptForRemoteInput: "); pw.println(mKeysKeptForRemoteInput); } public NotificationEntryManager(Context context) { Loading Loading @@ -374,6 +385,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count, true); NotificationData.Entry entry = mNotificationData.get(n.getKey()); if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(n.getKey())) { mKeysKeptForRemoteInput.remove(n.getKey()); } mRemoteInputManager.onPerformRemoveNotification(n, entry); final String pkg = n.getPackageName(); final String tag = n.getTag(); Loading Loading @@ -491,10 +508,35 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } if (updated) { Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key); mRemoteInputManager.getKeysKeptForRemoteInput().add(entry.key); addKeyKeptForRemoteInput(entry.key); return; } } if (FORCE_REMOTE_INPUT_HISTORY && shouldKeepForSmartReply(entry) && entry.row != null && !entry.row.isDismissed()) { // Turn off the spinner and hide buttons when an app cancels the notification. StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry); boolean updated = false; try { updateNotificationInternal(newSbn, null); updated = true; } catch (InflationException e) { // Ignore just don't keep the notification around. } // Treat the reply as longer sending. mSmartReplyController.stopSending(entry); if (updated) { Log.w(TAG, "Keeping notification around after sending smart reply " + entry.key); addKeyKeptForRemoteInput(entry.key); return; } } // Actually removing notification so smart reply controller can forget about it. mSmartReplyController.stopSending(entry); if (deferRemoval) { mLatestRankingMap = ranking; mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key)); Loading Loading @@ -536,6 +578,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. Notification.Builder b = Notification.Builder .recoverBuilder(mContext, sbn.getNotification().clone()); if (remoteInputText != null) { CharSequence[] oldHistory = sbn.getNotification().extras .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); CharSequence[] newHistory; Loading @@ -547,7 +590,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } newHistory[0] = String.valueOf(remoteInputText); b.setRemoteInputHistory(newHistory); } b.setShowRemoteInputSpinner(showSpinner); b.setHideSmartReplies(true); Notification newNotification = b.build(); Loading @@ -563,6 +608,17 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. return newSbn; } @VisibleForTesting StatusBarNotification rebuildNotificationForCanceledSmartReplies( NotificationData.Entry entry) { return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */, false /* showSpinner */); } private boolean shouldKeepForSmartReply(NotificationData.Entry entry) { return entry != null && mSmartReplyController.isSendingSmartReply(entry.key); } private boolean shouldKeepForRemoteInput(NotificationData.Entry entry) { if (entry == null) { return false; Loading Loading @@ -792,6 +848,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } mHeadsUpEntriesToRemoveOnSwitch.remove(entry); mRemoteInputManager.onUpdateNotification(entry); mSmartReplyController.stopSending(entry); if (key.equals(mGutsManager.getKeyToRemoveOnGutsClosed())) { mGutsManager.setKeyToRemoveOnGutsClosed(null); Loading Loading @@ -955,6 +1012,20 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. return mHeadsUpManager.isHeadsUp(key); } public boolean isNotificationKeptForRemoteInput(String key) { return mKeysKeptForRemoteInput.contains(key); } public void removeKeyKeptForRemoteInput(String key) { mKeysKeptForRemoteInput.remove(key); } public void addKeyKeptForRemoteInput(String key) { if (FORCE_REMOTE_INPUT_HISTORY) { mKeysKeptForRemoteInput.add(key); } } /** * Callback for NotificationEntryManager. */ Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java +1 −1 Original line number Diff line number Diff line Loading @@ -75,7 +75,7 @@ public class NotificationListener extends NotificationListenerWithPlugins { mPresenter.getHandler().post(() -> { processForRemoteInput(sbn.getNotification(), mContext); String key = sbn.getKey(); mRemoteInputManager.getKeysKeptForRemoteInput().remove(key); mEntryManager.removeKeyKeptForRemoteInput(key); boolean isUpdate = mEntryManager.getNotificationData().get(key) != null; // In case we don't allow child notifications, we ignore children of Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +2 −17 Original line number Diff line number Diff line Loading @@ -77,12 +77,6 @@ public class NotificationRemoteInputManager implements Dumpable { protected final NotificationLockscreenUserManager mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class); /** * Notifications with keys in this set are not actually around anymore. We kept them around * when they were canceled in response to a remote input interaction. This allows us to show * what you replied and allows you to continue typing into it. */ protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>(); protected final Context mContext; private final UserManager mUserManager; Loading Loading @@ -290,7 +284,8 @@ public class NotificationRemoteInputManager implements Dumpable { mRemoteInputController.addCallback(new RemoteInputController.Callback() { @Override public void onRemoteInputSent(NotificationData.Entry entry) { if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) { if (FORCE_REMOTE_INPUT_HISTORY && mEntryManager.isNotificationKeptForRemoteInput(entry.key)) { mEntryManager.removeNotification(entry.key, null); } else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) { // We're currently holding onto this notification, but from the apps point of Loading Loading @@ -340,10 +335,6 @@ public class NotificationRemoteInputManager implements Dumpable { if (mRemoteInputController.isRemoteInputActive(entry)) { mRemoteInputController.removeRemoteInput(entry, null); } if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(n.getKey())) { mKeysKeptForRemoteInput.remove(n.getKey()); } } public void removeRemoteInputEntriesKeptUntilCollapsed() { Loading @@ -368,8 +359,6 @@ public class NotificationRemoteInputManager implements Dumpable { pw.println("NotificationRemoteInputManager state:"); pw.print(" mRemoteInputEntriesToRemoveOnCollapse: "); pw.println(mRemoteInputEntriesToRemoveOnCollapse); pw.print(" mKeysKeptForRemoteInput: "); pw.println(mKeysKeptForRemoteInput); } public void bindRow(ExpandableNotificationRow row) { Loading @@ -377,10 +366,6 @@ public class NotificationRemoteInputManager implements Dumpable { row.setRemoteViewClickHandler(mOnClickHandler); } public Set<String> getKeysKeptForRemoteInput() { return mKeysKeptForRemoteInput; } @VisibleForTesting public Set<NotificationData.Entry> getRemoteInputEntriesToRemoveOnCollapse() { return mRemoteInputEntriesToRemoveOnCollapse; Loading