From 7997d7a0c562056e2a024ce35e3270afa4ea3981 Mon Sep 17 00:00:00 2001 From: Petr Cermak Date: Thu, 18 Jan 2018 15:52:10 +0000 Subject: Display smart replies in notifications If a notification contains a RemoteInput with non-empty choices, NotificationContentView will add a SmartReplyView to smart_reply_container in the expanded notification layout (if present). This feature is guarded behind Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS. Screenshot: https://screenshot.googleplex.com/jEzeL2ZYLMj.png Bug: 67765414 Test: Viewed a notification with smart replies from Android Messages Change-Id: I24d16df086edb58f51ae63830212d68166c74f52 --- .../statusbar/NotificationContentView.java | 63 ++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 64df92c3bd51..a4c17e3681b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -22,6 +22,7 @@ import android.app.RemoteInput; import android.content.Context; import android.graphics.Rect; import android.os.Build; +import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.util.AttributeSet; import android.util.Log; @@ -31,6 +32,7 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.NotificationColorUtil; @@ -42,6 +44,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.NotificationViewWrapper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.RemoteInputView; +import com.android.systemui.statusbar.policy.SmartReplyView; /** * A frame layout containing the actual payload of the notification, including the contracted, @@ -72,6 +75,7 @@ public class NotificationContentView extends FrameLayout { private RemoteInputView mExpandedRemoteInput; private RemoteInputView mHeadsUpRemoteInput; + private SmartReplyView mExpandedSmartReplyView; private NotificationViewWrapper mContractedWrapper; private NotificationViewWrapper mExpandedWrapper; @@ -1125,7 +1129,7 @@ public class NotificationContentView extends FrameLayout { if (mAmbientChild != null) { mAmbientWrapper.onContentUpdated(entry.row); } - applyRemoteInput(entry); + applyRemoteInputAndSmartReply(entry); updateLegacy(); mForceSelectNextLayout = true; setDark(mDark, false /* animate */, 0 /* delay */); @@ -1157,20 +1161,34 @@ public class NotificationContentView extends FrameLayout { } } - private void applyRemoteInput(final NotificationData.Entry entry) { + private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) { if (mRemoteInputController == null) { return; } + boolean enableSmartReplies = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS, 0) != 0; + boolean hasRemoteInput = false; + RemoteInput remoteInputWithChoices = null; + PendingIntent pendingIntentWithChoices = null; Notification.Action[] actions = entry.notification.getNotification().actions; if (actions != null) { for (Notification.Action a : actions) { if (a.getRemoteInputs() != null) { for (RemoteInput ri : a.getRemoteInputs()) { - if (ri.getAllowFreeFormInput()) { + boolean showRemoteInputView = ri.getAllowFreeFormInput(); + boolean showSmartReplyView = enableSmartReplies && ri.getChoices() != null + && ri.getChoices().length > 0; + if (showRemoteInputView) { hasRemoteInput = true; + } + if (showSmartReplyView) { + remoteInputWithChoices = ri; + pendingIntentWithChoices = a.actionIntent; + } + if (showRemoteInputView || showSmartReplyView) { break; } } @@ -1178,6 +1196,11 @@ public class NotificationContentView extends FrameLayout { } } + applyRemoteInput(entry, hasRemoteInput); + applySmartReplyView(remoteInputWithChoices, pendingIntentWithChoices); + } + + private void applyRemoteInput(NotificationData.Entry entry, boolean hasRemoteInput) { View bigContentView = mExpandedChild; if (bigContentView != null) { mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput, @@ -1274,6 +1297,40 @@ public class NotificationContentView extends FrameLayout { return null; } + private void applySmartReplyView(RemoteInput remoteInput, PendingIntent pendingIntent) { + mExpandedSmartReplyView = mExpandedChild == null ? + null : applySmartReplyView(mExpandedChild, remoteInput, pendingIntent); + } + + private SmartReplyView applySmartReplyView( + View view, RemoteInput remoteInput, PendingIntent pendingIntent) { + View smartReplyContainerCandidate = view.findViewById( + com.android.internal.R.id.smart_reply_container); + if (!(smartReplyContainerCandidate instanceof LinearLayout)) { + return null; + } + LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate; + if (remoteInput == null || pendingIntent == null) { + smartReplyContainer.setVisibility(View.GONE); + return null; + } + SmartReplyView smartReplyView = null; + if (smartReplyContainer.getChildCount() == 0) { + smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer); + smartReplyContainer.addView(smartReplyView); + } else if (smartReplyContainer.getChildCount() == 1) { + View child = smartReplyContainer.getChildAt(0); + if (child instanceof SmartReplyView) { + smartReplyView = (SmartReplyView) child; + } + } + if (smartReplyView != null) { + smartReplyView.setRepliesFromRemoteInput(remoteInput, pendingIntent); + smartReplyContainer.setVisibility(View.VISIBLE); + } + return smartReplyView; + } + public void closeRemoteInput() { if (mHeadsUpRemoteInput != null) { mHeadsUpRemoteInput.close(); -- cgit v1.2.3-59-g8ed1b