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.Main; 34 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 35 import com.android.systemui.util.DeviceConfigProxy; 36 37 import javax.inject.Inject; 38 39 /** 40 * Determines whether to show any indicators or controls related to notification assistant. 41 * 42 * Flags protect any changes from being shown. Notifications that are adjusted by the assistant 43 * should show an indicator. 44 */ 45 @SysUISingleton 46 public class AssistantFeedbackController { 47 private final Context mContext; 48 private final Handler mHandler; 49 private final DeviceConfigProxy mDeviceConfigProxy; 50 51 public static final int STATUS_UNCHANGED = 0; 52 public static final int STATUS_ALERTED = 1; 53 public static final int STATUS_SILENCED = 2; 54 public static final int STATUS_PROMOTED = 3; 55 public static final int STATUS_DEMOTED = 4; 56 57 private final SparseArray<FeedbackIcon> mIcons; 58 59 private volatile boolean mFeedbackEnabled; 60 61 private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener = 62 new DeviceConfig.OnPropertiesChangedListener() { 63 @Override 64 public void onPropertiesChanged(DeviceConfig.Properties properties) { 65 if (properties.getKeyset().contains(ENABLE_NAS_FEEDBACK)) { 66 mFeedbackEnabled = properties.getBoolean( 67 ENABLE_NAS_FEEDBACK, false); 68 } 69 } 70 }; 71 72 /** Injected constructor */ 73 @Inject AssistantFeedbackController(@ain Handler handler, Context context, DeviceConfigProxy proxy)74 public AssistantFeedbackController(@Main Handler handler, 75 Context context, DeviceConfigProxy proxy) { 76 mHandler = handler; 77 mContext = context; 78 mDeviceConfigProxy = proxy; 79 mFeedbackEnabled = mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, 80 ENABLE_NAS_FEEDBACK, false); 81 mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, 82 this::postToHandler, mPropertiesChangedListener); 83 // Populate the array of statuses. 84 mIcons = new SparseArray<>(4); 85 mIcons.set(STATUS_ALERTED, new FeedbackIcon(R.drawable.ic_feedback_alerted, 86 R.string.notification_feedback_indicator_alerted)); 87 mIcons.set(STATUS_SILENCED, new FeedbackIcon(R.drawable.ic_feedback_silenced, 88 R.string.notification_feedback_indicator_silenced)); 89 mIcons.set(STATUS_PROMOTED, new FeedbackIcon(R.drawable.ic_feedback_uprank, 90 R.string.notification_feedback_indicator_promoted)); 91 mIcons.set(STATUS_DEMOTED, new FeedbackIcon(R.drawable.ic_feedback_downrank, 92 R.string.notification_feedback_indicator_demoted)); 93 } 94 postToHandler(Runnable r)95 private void postToHandler(Runnable r) { 96 this.mHandler.post(r); 97 } 98 99 /** 100 * Determines whether to show any user controls related to the assistant based on the 101 * DeviceConfig flag value 102 */ isFeedbackEnabled()103 public boolean isFeedbackEnabled() { 104 return mFeedbackEnabled; 105 } 106 107 /** 108 * Get the feedback status according to assistant's adjustments 109 * 110 * @param entry Notification Entry to show feedback for 111 */ getFeedbackStatus(NotificationEntry entry)112 public int getFeedbackStatus(NotificationEntry entry) { 113 if (!isFeedbackEnabled()) { 114 return STATUS_UNCHANGED; 115 } 116 Ranking ranking = entry.getRanking(); 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 entry Notification Entry to show feedback for 141 */ 142 @Nullable getFeedbackIcon(NotificationEntry entry)143 public FeedbackIcon getFeedbackIcon(NotificationEntry entry) { 144 int feedbackStatus = getFeedbackStatus(entry); 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 entry Notification Entry to show feedback for 153 */ getInlineDescriptionResource(NotificationEntry entry)154 public int getInlineDescriptionResource(NotificationEntry entry) { 155 int feedbackStatus = getFeedbackStatus(entry); 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