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