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