1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 package com.android.systemui.statusbar;
17 
18 import android.app.Notification;
19 import android.os.RemoteException;
20 import android.util.ArraySet;
21 
22 import androidx.annotation.NonNull;
23 
24 import com.android.internal.statusbar.IStatusBarService;
25 import com.android.internal.statusbar.NotificationVisibility;
26 import com.android.systemui.Dumpable;
27 import com.android.systemui.dump.DumpManager;
28 import com.android.systemui.statusbar.dagger.StatusBarModule;
29 import com.android.systemui.statusbar.notification.NotificationEntryManager;
30 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
31 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
32 
33 import java.io.FileDescriptor;
34 import java.io.PrintWriter;
35 import java.util.Set;
36 
37 /**
38  * Handles when smart replies are added to a notification
39  * and clicked upon.
40  */
41 public class SmartReplyController implements Dumpable {
42     private final IStatusBarService mBarService;
43     private final NotificationEntryManager mEntryManager;
44     private final NotificationClickNotifier mClickNotifier;
45     private final Set<String> mSendingKeys = new ArraySet<>();
46     private Callback mCallback;
47 
48     /**
49      * Injected constructor. See {@link StatusBarModule}.
50      */
SmartReplyController( DumpManager dumpManager, NotificationEntryManager entryManager, IStatusBarService statusBarService, NotificationClickNotifier clickNotifier)51     public SmartReplyController(
52             DumpManager dumpManager,
53             NotificationEntryManager entryManager,
54             IStatusBarService statusBarService,
55             NotificationClickNotifier clickNotifier) {
56         mBarService = statusBarService;
57         mEntryManager = entryManager;
58         mClickNotifier = clickNotifier;
59         dumpManager.registerDumpable(this);
60     }
61 
setCallback(Callback callback)62     public void setCallback(Callback callback) {
63         mCallback = callback;
64     }
65 
66     /**
67      * Notifies StatusBarService a smart reply is sent.
68      */
smartReplySent(NotificationEntry entry, int replyIndex, CharSequence reply, int notificationLocation, boolean modifiedBeforeSending)69     public void smartReplySent(NotificationEntry entry, int replyIndex, CharSequence reply,
70             int notificationLocation, boolean modifiedBeforeSending) {
71         mCallback.onSmartReplySent(entry, reply);
72         mSendingKeys.add(entry.getKey());
73         try {
74             mBarService.onNotificationSmartReplySent(entry.getSbn().getKey(), replyIndex, reply,
75                     notificationLocation, modifiedBeforeSending);
76         } catch (RemoteException e) {
77             // Nothing to do, system going down
78         }
79     }
80 
81     /**
82      * Notifies StatusBarService a smart action is clicked.
83      */
smartActionClicked( NotificationEntry entry, int actionIndex, Notification.Action action, boolean generatedByAssistant)84     public void smartActionClicked(
85             NotificationEntry entry, int actionIndex, Notification.Action action,
86             boolean generatedByAssistant) {
87         // TODO(b/204183781): get this from the current pipeline
88         final int count = mEntryManager.getActiveNotificationsCount();
89         final int rank = entry.getRanking().getRank();
90         NotificationVisibility.NotificationLocation location =
91                 NotificationLogger.getNotificationLocation(entry);
92         final NotificationVisibility nv = NotificationVisibility.obtain(
93                 entry.getKey(), rank, count, true, location);
94         mClickNotifier.onNotificationActionClick(
95                 entry.getKey(), actionIndex, action, nv, generatedByAssistant);
96     }
97 
98     /**
99      * Have we posted an intent to an app about sending a smart reply from the
100      * notification with this key.
101      */
isSendingSmartReply(String key)102     public boolean isSendingSmartReply(String key) {
103         return mSendingKeys.contains(key);
104     }
105 
106     /**
107      * Smart Replies and Actions have been added to the UI.
108      */
smartSuggestionsAdded(final NotificationEntry entry, int replyCount, int actionCount, boolean generatedByAssistant, boolean editBeforeSending)109     public void smartSuggestionsAdded(final NotificationEntry entry, int replyCount,
110             int actionCount, boolean generatedByAssistant, boolean editBeforeSending) {
111         try {
112             mBarService.onNotificationSmartSuggestionsAdded(entry.getSbn().getKey(), replyCount,
113                     actionCount, generatedByAssistant, editBeforeSending);
114         } catch (RemoteException e) {
115             // Nothing to do, system going down
116         }
117     }
118 
stopSending(final NotificationEntry entry)119     public void stopSending(final NotificationEntry entry) {
120         if (entry != null) {
121             mSendingKeys.remove(entry.getSbn().getKey());
122         }
123     }
124 
125     @Override
dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args)126     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
127         pw.println("mSendingKeys: " + mSendingKeys.size());
128         for (String key : mSendingKeys) {
129             pw.println(" * " + key);
130         }
131     }
132 
133     /**
134      * Callback for any class that needs to do something in response to a smart reply being sent.
135      */
136     public interface Callback {
137         /**
138          * A smart reply has just been sent for a notification
139          *
140          * @param entry the entry for the notification
141          * @param reply the reply that was sent
142          */
onSmartReplySent(NotificationEntry entry, CharSequence reply)143         void onSmartReplySent(NotificationEntry entry, CharSequence reply);
144     }
145 }
146