• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.systemui.statusbar.notification;
18 
19 import static android.service.notification.NotificationListenerService.Ranking;
20 
21 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.ENABLE_NAS_FEEDBACK;
22 
23 import android.app.NotificationManager;
24 import android.content.Context;
25 import android.os.Handler;
26 import android.provider.DeviceConfig;
27 import android.util.SparseArray;
28 
29 import androidx.annotation.Nullable;
30 
31 import com.android.internal.R;
32 import com.android.systemui.dagger.SysUISingleton;
33 import com.android.systemui.dagger.qualifiers.Application;
34 import com.android.systemui.dagger.qualifiers.Main;
35 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
36 import com.android.systemui.util.DeviceConfigProxy;
37 
38 import javax.inject.Inject;
39 
40 /**
41  * Determines whether to show any indicators or controls related to notification assistant.
42  *
43  * Flags protect any changes from being shown. Notifications that are adjusted by the assistant
44  * should show an indicator.
45  */
46 @SysUISingleton
47 public class AssistantFeedbackController {
48     private final Context mContext;
49     private final Handler mHandler;
50     private final DeviceConfigProxy mDeviceConfigProxy;
51 
52     public static final int STATUS_UNCHANGED = 0;
53     public static final int STATUS_ALERTED = 1;
54     public static final int STATUS_SILENCED = 2;
55     public static final int STATUS_PROMOTED = 3;
56     public static final int STATUS_DEMOTED = 4;
57 
58     private final SparseArray<FeedbackIcon> mIcons;
59 
60     private volatile boolean mFeedbackEnabled;
61 
62     private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
63             new DeviceConfig.OnPropertiesChangedListener() {
64                 @Override
65                 public void onPropertiesChanged(DeviceConfig.Properties properties) {
66                     if (properties.getKeyset().contains(ENABLE_NAS_FEEDBACK)) {
67                         mFeedbackEnabled = properties.getBoolean(
68                                 ENABLE_NAS_FEEDBACK, false);
69                     }
70                 }
71             };
72 
73     /** Injected constructor */
74     @Inject
AssistantFeedbackController(@ain Handler handler, @Application Context context, DeviceConfigProxy proxy)75     public AssistantFeedbackController(@Main Handler handler,
76             @Application Context context, DeviceConfigProxy proxy) {
77         mHandler = handler;
78         mContext = context;
79         mDeviceConfigProxy = proxy;
80         mFeedbackEnabled = mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
81                 ENABLE_NAS_FEEDBACK, false);
82         mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
83                 this::postToHandler, mPropertiesChangedListener);
84         // Populate the array of statuses.
85         mIcons = new SparseArray<>(4);
86         mIcons.set(STATUS_ALERTED, new FeedbackIcon(R.drawable.ic_feedback_alerted,
87                 R.string.notification_feedback_indicator_alerted));
88         mIcons.set(STATUS_SILENCED, new FeedbackIcon(R.drawable.ic_feedback_silenced,
89                 R.string.notification_feedback_indicator_silenced));
90         mIcons.set(STATUS_PROMOTED, new FeedbackIcon(R.drawable.ic_feedback_uprank,
91                 R.string.notification_feedback_indicator_promoted));
92         mIcons.set(STATUS_DEMOTED, new FeedbackIcon(R.drawable.ic_feedback_downrank,
93                 R.string.notification_feedback_indicator_demoted));
94     }
95 
postToHandler(Runnable r)96     private void postToHandler(Runnable r) {
97         this.mHandler.post(r);
98     }
99 
100     /**
101      * Determines whether to show any user controls related to the assistant based on the
102      * DeviceConfig flag value
103      */
isFeedbackEnabled()104     public boolean isFeedbackEnabled() {
105         return mFeedbackEnabled;
106     }
107 
108     /**
109      * Get the feedback status according to assistant's adjustments
110      *
111      * @param ranking Ranking of the notification show feedback for
112      */
getFeedbackStatus(Ranking ranking)113     public int getFeedbackStatus(Ranking ranking) {
114         if (!isFeedbackEnabled()) {
115             return STATUS_UNCHANGED;
116         }
117         int oldImportance = ranking.getChannel().getImportance();
118         int newImportance = ranking.getImportance();
119         if (oldImportance < NotificationManager.IMPORTANCE_DEFAULT
120                 && newImportance >= NotificationManager.IMPORTANCE_DEFAULT) {
121             return STATUS_ALERTED;
122         } else if (oldImportance >= NotificationManager.IMPORTANCE_DEFAULT
123                 && newImportance < NotificationManager.IMPORTANCE_DEFAULT) {
124             return STATUS_SILENCED;
125         } else if (oldImportance < newImportance
126                 || ranking.getRankingAdjustment() == Ranking.RANKING_PROMOTED) {
127             return STATUS_PROMOTED;
128         } else if (oldImportance > newImportance
129                 || ranking.getRankingAdjustment() == Ranking.RANKING_DEMOTED) {
130             return STATUS_DEMOTED;
131         } else {
132             return STATUS_UNCHANGED;
133         }
134     }
135 
136     /**
137      * Get the feedback indicator image and content description resources according to assistant's
138      * changes on this notification's rank or importance.
139      *
140      * @param ranking Ranking of the notification to show feedback for
141      */
142     @Nullable
getFeedbackIcon(Ranking ranking)143     public FeedbackIcon getFeedbackIcon(Ranking ranking) {
144         int feedbackStatus = getFeedbackStatus(ranking);
145         return mIcons.get(feedbackStatus);
146     }
147 
148     /**
149      * Get the inline settings description resource according to assistant's changes on this
150      * notification's rank or importance.
151      *
152      * @param ranking Ranking of the notification to show feedback for
153      */
getInlineDescriptionResource(Ranking ranking)154     public int getInlineDescriptionResource(Ranking ranking) {
155         int feedbackStatus = getFeedbackStatus(ranking);
156         switch (feedbackStatus) {
157             case STATUS_ALERTED:
158                 return com.android.systemui.res.R.string.notification_channel_summary_automatic_alerted;
159             case STATUS_SILENCED:
160                 return com.android.systemui.res.R.string
161                         .notification_channel_summary_automatic_silenced;
162             case STATUS_PROMOTED:
163                 return com.android.systemui.res.R.string
164                         .notification_channel_summary_automatic_promoted;
165             case STATUS_DEMOTED:
166                 return com.android.systemui.res.R.string.notification_channel_summary_automatic_demoted;
167             default:
168                 return com.android.systemui.res.R.string.notification_channel_summary_automatic;
169         }
170     }
171 }
172