Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 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.row; |
| 18 | |
| 19 | import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION; |
Mady Mellor | a92268c | 2020-03-09 17:25:08 -0700 | [diff] [blame] | 20 | import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; |
| 21 | import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 22 | import static android.app.NotificationManager.IMPORTANCE_DEFAULT; |
| 23 | import static android.app.NotificationManager.IMPORTANCE_LOW; |
| 24 | import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 25 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 26 | import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN; |
| 27 | |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 28 | import static java.lang.annotation.RetentionPolicy.SOURCE; |
| 29 | |
| 30 | import android.annotation.IntDef; |
| 31 | import android.annotation.NonNull; |
| 32 | import android.app.INotificationManager; |
| 33 | import android.app.Notification; |
| 34 | import android.app.NotificationChannel; |
| 35 | import android.app.NotificationChannelGroup; |
| 36 | import android.content.Context; |
| 37 | import android.content.Intent; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 38 | import android.content.pm.ApplicationInfo; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 39 | import android.content.pm.PackageManager; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 40 | import android.content.pm.ShortcutInfo; |
| 41 | import android.content.pm.ShortcutManager; |
| 42 | import android.graphics.drawable.Icon; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 43 | import android.os.Handler; |
| 44 | import android.os.Parcelable; |
| 45 | import android.os.RemoteException; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 46 | import android.service.notification.StatusBarNotification; |
| 47 | import android.text.TextUtils; |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 48 | import android.transition.ChangeBounds; |
| 49 | import android.transition.Fade; |
| 50 | import android.transition.TransitionManager; |
| 51 | import android.transition.TransitionSet; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 52 | import android.util.AttributeSet; |
| 53 | import android.util.Log; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 54 | import android.view.View; |
| 55 | import android.view.accessibility.AccessibilityEvent; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 56 | import android.widget.ImageView; |
| 57 | import android.widget.LinearLayout; |
| 58 | import android.widget.TextView; |
| 59 | |
| 60 | import com.android.internal.annotations.VisibleForTesting; |
Julia Reynolds | 01c9da4 | 2020-02-14 14:17:58 -0500 | [diff] [blame] | 61 | import com.android.settingslib.notification.ConversationIconFactory; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 62 | import com.android.systemui.Dependency; |
| 63 | import com.android.systemui.R; |
Mady Mellor | 9adfe6a | 2020-03-30 17:23:26 -0700 | [diff] [blame] | 64 | import com.android.systemui.statusbar.notification.NotificationChannelHelper; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 65 | import com.android.systemui.statusbar.notification.VisualStabilityManager; |
| 66 | import com.android.systemui.statusbar.notification.collection.NotificationEntry; |
| 67 | |
| 68 | import java.lang.annotation.Retention; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 69 | import java.util.List; |
| 70 | |
| 71 | /** |
| 72 | * The guts of a conversation notification revealed when performing a long press. |
| 73 | */ |
| 74 | public class NotificationConversationInfo extends LinearLayout implements |
| 75 | NotificationGuts.GutsContent { |
| 76 | private static final String TAG = "ConversationGuts"; |
| 77 | |
| 78 | |
| 79 | private INotificationManager mINotificationManager; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 80 | ShortcutManager mShortcutManager; |
| 81 | private PackageManager mPm; |
| 82 | private VisualStabilityManager mVisualStabilityManager; |
Julia Reynolds | 01c9da4 | 2020-02-14 14:17:58 -0500 | [diff] [blame] | 83 | private ConversationIconFactory mIconFactory; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 84 | |
| 85 | private String mPackageName; |
| 86 | private String mAppName; |
| 87 | private int mAppUid; |
| 88 | private String mDelegatePkg; |
| 89 | private NotificationChannel mNotificationChannel; |
| 90 | private ShortcutInfo mShortcutInfo; |
| 91 | private String mConversationId; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 92 | private StatusBarNotification mSbn; |
| 93 | private boolean mIsDeviceProvisioned; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 94 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 95 | private TextView mPriorityDescriptionView; |
| 96 | private TextView mDefaultDescriptionView; |
| 97 | private TextView mSilentDescriptionView; |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 98 | private @Action int mSelectedAction = -1; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 99 | |
| 100 | private OnSnoozeClickListener mOnSnoozeClickListener; |
| 101 | private OnSettingsClickListener mOnSettingsClickListener; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 102 | private NotificationGuts mGutsContainer; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 103 | |
| 104 | @VisibleForTesting |
| 105 | boolean mSkipPost = false; |
| 106 | |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 107 | @Retention(SOURCE) |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 108 | @IntDef({ACTION_DEFAULT, ACTION_HOME, ACTION_FAVORITE, ACTION_SNOOZE, ACTION_MUTE, |
| 109 | ACTION_SETTINGS}) |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 110 | private @interface Action {} |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 111 | static final int ACTION_DEFAULT = 0; |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 112 | static final int ACTION_HOME = 1; |
| 113 | static final int ACTION_FAVORITE = 2; |
| 114 | static final int ACTION_SNOOZE = 3; |
| 115 | static final int ACTION_MUTE = 4; |
| 116 | static final int ACTION_SETTINGS = 5; |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 117 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 118 | // TODO: b/152050825 |
| 119 | /* |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 120 | private OnClickListener mOnHomeClick = v -> { |
| 121 | mSelectedAction = ACTION_HOME; |
| 122 | mShortcutManager.requestPinShortcut(mShortcutInfo, null); |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 123 | mShadeController.animateCollapsePanels(); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 124 | closeControls(v, true); |
| 125 | }; |
| 126 | |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 127 | private OnClickListener mOnSnoozeClick = v -> { |
| 128 | mSelectedAction = ACTION_SNOOZE; |
| 129 | mOnSnoozeClickListener.onClick(v, 1); |
| 130 | closeControls(v, true); |
| 131 | }; |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 132 | */ |
| 133 | |
| 134 | private OnClickListener mOnFavoriteClick = v -> { |
| 135 | mSelectedAction = ACTION_FAVORITE; |
| 136 | updateToggleActions(mSelectedAction, true); |
| 137 | }; |
| 138 | |
| 139 | private OnClickListener mOnDefaultClick = v -> { |
| 140 | mSelectedAction = ACTION_DEFAULT; |
| 141 | updateToggleActions(mSelectedAction, true); |
| 142 | }; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 143 | |
| 144 | private OnClickListener mOnMuteClick = v -> { |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 145 | mSelectedAction = ACTION_MUTE; |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 146 | updateToggleActions(mSelectedAction, true); |
| 147 | }; |
| 148 | |
| 149 | private OnClickListener mOnDone = v -> { |
| 150 | closeControls(v, true); |
Julia Reynolds | dcd70d6 | 2020-01-15 10:33:43 -0500 | [diff] [blame] | 151 | }; |
| 152 | |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 153 | public NotificationConversationInfo(Context context, AttributeSet attrs) { |
| 154 | super(context, attrs); |
| 155 | } |
| 156 | |
| 157 | public interface OnSettingsClickListener { |
| 158 | void onClick(View v, NotificationChannel channel, int appUid); |
| 159 | } |
| 160 | |
| 161 | public interface OnAppSettingsClickListener { |
| 162 | void onClick(View v, Intent intent); |
| 163 | } |
| 164 | |
| 165 | public interface OnSnoozeClickListener { |
| 166 | void onClick(View v, int hoursToSnooze); |
| 167 | } |
| 168 | |
| 169 | public void bindNotification( |
| 170 | ShortcutManager shortcutManager, |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 171 | PackageManager pm, |
| 172 | INotificationManager iNotificationManager, |
| 173 | VisualStabilityManager visualStabilityManager, |
| 174 | String pkg, |
| 175 | NotificationChannel notificationChannel, |
| 176 | NotificationEntry entry, |
| 177 | OnSettingsClickListener onSettingsClick, |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 178 | OnSnoozeClickListener onSnoozeClickListener, |
Julia Reynolds | 01c9da4 | 2020-02-14 14:17:58 -0500 | [diff] [blame] | 179 | ConversationIconFactory conversationIconFactory, |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 180 | boolean isDeviceProvisioned) { |
| 181 | mSelectedAction = -1; |
| 182 | mINotificationManager = iNotificationManager; |
| 183 | mVisualStabilityManager = visualStabilityManager; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 184 | mPackageName = pkg; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 185 | mSbn = entry.getSbn(); |
| 186 | mPm = pm; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 187 | mAppName = mPackageName; |
| 188 | mOnSettingsClickListener = onSettingsClick; |
| 189 | mNotificationChannel = notificationChannel; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 190 | mAppUid = mSbn.getUid(); |
| 191 | mDelegatePkg = mSbn.getOpPkg(); |
| 192 | mIsDeviceProvisioned = isDeviceProvisioned; |
| 193 | mOnSnoozeClickListener = onSnoozeClickListener; |
Julia Reynolds | 01c9da4 | 2020-02-14 14:17:58 -0500 | [diff] [blame] | 194 | mIconFactory = conversationIconFactory; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 195 | |
| 196 | mShortcutManager = shortcutManager; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 197 | mConversationId = mNotificationChannel.getConversationId(); |
| 198 | if (TextUtils.isEmpty(mNotificationChannel.getConversationId())) { |
Julia Reynolds | 7c26752 | 2020-01-16 11:26:41 -0500 | [diff] [blame] | 199 | mConversationId = mSbn.getShortcutId(mContext); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 200 | } |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 201 | if (TextUtils.isEmpty(mConversationId)) { |
Julia Reynolds | 7c26752 | 2020-01-16 11:26:41 -0500 | [diff] [blame] | 202 | throw new IllegalArgumentException("Does not have required information"); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 203 | } |
Julia Reynolds | 138111f | 2020-02-26 11:17:39 -0500 | [diff] [blame] | 204 | mShortcutInfo = entry.getRanking().getShortcutInfo(); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 205 | |
Mady Mellor | 9adfe6a | 2020-03-30 17:23:26 -0700 | [diff] [blame] | 206 | mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded( |
| 207 | getContext(), mINotificationManager, entry, mNotificationChannel); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 208 | |
| 209 | bindHeader(); |
| 210 | bindActions(); |
| 211 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 212 | View done = findViewById(R.id.done); |
| 213 | done.setOnClickListener(mOnDone); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 214 | } |
| 215 | |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 216 | private void bindActions() { |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 217 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 218 | // TODO: b/152050825 |
| 219 | /* |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 220 | Button home = findViewById(R.id.home); |
| 221 | home.setOnClickListener(mOnHomeClick); |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 222 | home.setVisibility(mShortcutInfo != null |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 223 | && mShortcutManager.isRequestPinShortcutSupported() |
| 224 | ? VISIBLE : GONE); |
| 225 | |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 226 | Button snooze = findViewById(R.id.snooze); |
| 227 | snooze.setOnClickListener(mOnSnoozeClick); |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 228 | */ |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 229 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 230 | findViewById(R.id.priority).setOnClickListener(mOnFavoriteClick); |
| 231 | findViewById(R.id.default_behavior).setOnClickListener(mOnDefaultClick); |
| 232 | findViewById(R.id.silence).setOnClickListener(mOnMuteClick); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 233 | |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 234 | final View settingsButton = findViewById(R.id.info); |
| 235 | settingsButton.setOnClickListener(getSettingsOnClickListener()); |
| 236 | settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE); |
| 237 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 238 | updateToggleActions(getSelectedAction(), false); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 239 | } |
| 240 | |
| 241 | private void bindHeader() { |
| 242 | bindConversationDetails(); |
| 243 | |
| 244 | // Delegate |
| 245 | bindDelegate(); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | private OnClickListener getSettingsOnClickListener() { |
| 249 | if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) { |
| 250 | final int appUidF = mAppUid; |
| 251 | return ((View view) -> { |
| 252 | mOnSettingsClickListener.onClick(view, mNotificationChannel, appUidF); |
| 253 | }); |
| 254 | } |
| 255 | return null; |
| 256 | } |
| 257 | |
| 258 | private void bindConversationDetails() { |
| 259 | final TextView channelName = findViewById(R.id.parent_channel_name); |
| 260 | channelName.setText(mNotificationChannel.getName()); |
| 261 | |
| 262 | bindGroup(); |
Julia Reynolds | f2acd60 | 2020-01-21 16:01:25 -0500 | [diff] [blame] | 263 | // TODO: bring back when channel name does not include name |
| 264 | // bindName(); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 265 | bindPackage(); |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 266 | bindIcon(mNotificationChannel.isImportantConversation()); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 267 | |
| 268 | } |
| 269 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 270 | private void bindIcon(boolean important) { |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 271 | ImageView image = findViewById(R.id.conversation_icon); |
| 272 | if (mShortcutInfo != null) { |
Dan Sandler | b11f2de | 2020-02-19 13:18:24 -0500 | [diff] [blame] | 273 | image.setImageDrawable(mIconFactory.getConversationDrawable( |
| 274 | mShortcutInfo, mPackageName, mAppUid, |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 275 | important)); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 276 | } else { |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 277 | if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) { |
| 278 | // TODO: maybe use a generic group icon, or a composite of recent senders |
| 279 | image.setImageDrawable(mPm.getDefaultActivityIcon()); |
| 280 | } else { |
| 281 | final List<Notification.MessagingStyle.Message> messages = |
| 282 | Notification.MessagingStyle.Message.getMessagesFromBundleArray( |
| 283 | (Parcelable[]) mSbn.getNotification().extras.get( |
| 284 | Notification.EXTRA_MESSAGES)); |
| 285 | |
| 286 | final Notification.MessagingStyle.Message latestMessage = |
| 287 | Notification.MessagingStyle.findLatestIncomingMessage(messages); |
| 288 | Icon personIcon = latestMessage.getSenderPerson().getIcon(); |
| 289 | if (personIcon != null) { |
| 290 | image.setImageIcon(latestMessage.getSenderPerson().getIcon()); |
| 291 | } else { |
| 292 | // TODO: choose something better |
| 293 | image.setImageDrawable(mPm.getDefaultActivityIcon()); |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 299 | private void bindPackage() { |
| 300 | ApplicationInfo info; |
| 301 | try { |
| 302 | info = mPm.getApplicationInfo( |
| 303 | mPackageName, |
| 304 | PackageManager.MATCH_UNINSTALLED_PACKAGES |
| 305 | | PackageManager.MATCH_DISABLED_COMPONENTS |
| 306 | | PackageManager.MATCH_DIRECT_BOOT_UNAWARE |
| 307 | | PackageManager.MATCH_DIRECT_BOOT_AWARE); |
| 308 | if (info != null) { |
| 309 | mAppName = String.valueOf(mPm.getApplicationLabel(info)); |
| 310 | } |
| 311 | } catch (PackageManager.NameNotFoundException e) { |
| 312 | } |
| 313 | ((TextView) findViewById(R.id.pkg_name)).setText(mAppName); |
| 314 | } |
| 315 | |
| 316 | private void bindDelegate() { |
| 317 | TextView delegateView = findViewById(R.id.delegate_name); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 318 | |
| 319 | if (!TextUtils.equals(mPackageName, mDelegatePkg)) { |
| 320 | // this notification was posted by a delegate! |
| 321 | delegateView.setVisibility(View.VISIBLE); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 322 | } else { |
| 323 | delegateView.setVisibility(View.GONE); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 324 | } |
| 325 | } |
| 326 | |
| 327 | private void bindGroup() { |
| 328 | // Set group information if this channel has an associated group. |
| 329 | CharSequence groupName = null; |
| 330 | if (mNotificationChannel != null && mNotificationChannel.getGroup() != null) { |
| 331 | try { |
| 332 | final NotificationChannelGroup notificationChannelGroup = |
| 333 | mINotificationManager.getNotificationChannelGroupForPackage( |
| 334 | mNotificationChannel.getGroup(), mPackageName, mAppUid); |
| 335 | if (notificationChannelGroup != null) { |
| 336 | groupName = notificationChannelGroup.getName(); |
| 337 | } |
| 338 | } catch (RemoteException e) { |
| 339 | } |
| 340 | } |
| 341 | TextView groupNameView = findViewById(R.id.group_name); |
| 342 | View groupDivider = findViewById(R.id.group_divider); |
| 343 | if (groupName != null) { |
| 344 | groupNameView.setText(groupName); |
| 345 | groupNameView.setVisibility(VISIBLE); |
| 346 | groupDivider.setVisibility(VISIBLE); |
| 347 | } else { |
| 348 | groupNameView.setVisibility(GONE); |
| 349 | groupDivider.setVisibility(GONE); |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | @Override |
| 354 | public boolean post(Runnable action) { |
| 355 | if (mSkipPost) { |
| 356 | action.run(); |
| 357 | return true; |
| 358 | } else { |
| 359 | return super.post(action); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | @Override |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 364 | protected void onFinishInflate() { |
| 365 | super.onFinishInflate(); |
| 366 | |
| 367 | mPriorityDescriptionView = findViewById(R.id.priority_summary); |
| 368 | mDefaultDescriptionView = findViewById(R.id.default_summary); |
| 369 | mSilentDescriptionView = findViewById(R.id.silence_summary); |
| 370 | } |
| 371 | |
| 372 | @Override |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 373 | public void onFinishedClosing() { |
| 374 | // TODO: do we need to do anything here? |
| 375 | } |
| 376 | |
| 377 | @Override |
| 378 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) { |
| 379 | super.onInitializeAccessibilityEvent(event); |
| 380 | if (mGutsContainer != null && |
| 381 | event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { |
| 382 | if (mGutsContainer.isExposed()) { |
| 383 | event.getText().add(mContext.getString( |
| 384 | R.string.notification_channel_controls_opened_accessibility, mAppName)); |
| 385 | } else { |
| 386 | event.getText().add(mContext.getString( |
| 387 | R.string.notification_channel_controls_closed_accessibility, mAppName)); |
| 388 | } |
| 389 | } |
| 390 | } |
| 391 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 392 | private void updateToggleActions(int selectedAction, boolean userTriggered) { |
| 393 | if (userTriggered) { |
| 394 | TransitionSet transition = new TransitionSet(); |
| 395 | transition.setOrdering(TransitionSet.ORDERING_TOGETHER); |
| 396 | transition.addTransition(new Fade(Fade.OUT)) |
| 397 | .addTransition(new ChangeBounds()) |
| 398 | .addTransition( |
| 399 | new Fade(Fade.IN) |
| 400 | .setStartDelay(150) |
| 401 | .setDuration(200) |
| 402 | .setInterpolator(FAST_OUT_SLOW_IN)); |
| 403 | transition.setDuration(350); |
| 404 | transition.setInterpolator(FAST_OUT_SLOW_IN); |
| 405 | TransitionManager.beginDelayedTransition(this, transition); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 406 | } |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 407 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 408 | View priority = findViewById(R.id.priority); |
| 409 | View defaultBehavior = findViewById(R.id.default_behavior); |
| 410 | View silence = findViewById(R.id.silence); |
| 411 | |
| 412 | switch (selectedAction) { |
| 413 | case ACTION_FAVORITE: |
| 414 | mPriorityDescriptionView.setVisibility(VISIBLE); |
| 415 | mDefaultDescriptionView.setVisibility(GONE); |
| 416 | mSilentDescriptionView.setVisibility(GONE); |
| 417 | post(() -> { |
| 418 | priority.setSelected(true); |
| 419 | defaultBehavior.setSelected(false); |
| 420 | silence.setSelected(false); |
| 421 | }); |
| 422 | break; |
| 423 | |
| 424 | case ACTION_MUTE: |
| 425 | mSilentDescriptionView.setVisibility(VISIBLE); |
| 426 | mDefaultDescriptionView.setVisibility(GONE); |
| 427 | mPriorityDescriptionView.setVisibility(GONE); |
| 428 | post(() -> { |
| 429 | priority.setSelected(false); |
| 430 | defaultBehavior.setSelected(false); |
| 431 | silence.setSelected(true); |
| 432 | }); |
| 433 | break; |
| 434 | |
| 435 | case ACTION_DEFAULT: |
| 436 | mDefaultDescriptionView.setVisibility(VISIBLE); |
| 437 | mSilentDescriptionView.setVisibility(GONE); |
| 438 | mPriorityDescriptionView.setVisibility(GONE); |
| 439 | post(() -> { |
| 440 | priority.setSelected(false); |
| 441 | defaultBehavior.setSelected(true); |
| 442 | silence.setSelected(false); |
| 443 | }); |
| 444 | break; |
| 445 | |
| 446 | default: |
| 447 | throw new IllegalArgumentException("Unrecognized behavior: " + mSelectedAction); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 448 | } |
Dan Sandler | b11f2de | 2020-02-19 13:18:24 -0500 | [diff] [blame] | 449 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 450 | boolean isAChange = getSelectedAction() != selectedAction; |
| 451 | TextView done = findViewById(R.id.done); |
| 452 | done.setText(isAChange |
| 453 | ? R.string.inline_ok_button |
| 454 | : R.string.inline_done_button); |
| 455 | |
Dan Sandler | b11f2de | 2020-02-19 13:18:24 -0500 | [diff] [blame] | 456 | // update icon in case importance has changed |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 457 | bindIcon(selectedAction == ACTION_FAVORITE); |
| 458 | } |
| 459 | |
| 460 | int getSelectedAction() { |
| 461 | if (mNotificationChannel.getImportance() <= IMPORTANCE_LOW |
| 462 | && mNotificationChannel.getImportance() > IMPORTANCE_UNSPECIFIED) { |
| 463 | return ACTION_MUTE; |
| 464 | } else { |
| 465 | if (mNotificationChannel.isImportantConversation()) { |
| 466 | return ACTION_FAVORITE; |
| 467 | } |
| 468 | } |
| 469 | return ACTION_DEFAULT; |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | private void updateChannel() { |
| 473 | Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER)); |
| 474 | bgHandler.post( |
| 475 | new UpdateChannelRunnable(mINotificationManager, mPackageName, |
| 476 | mAppUid, mSelectedAction, mNotificationChannel)); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 477 | } |
| 478 | |
| 479 | /** |
| 480 | * Closes the controls and commits the updated importance values (indirectly). |
| 481 | * |
| 482 | * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the |
| 483 | * user does not have the ability to undo the action anymore. |
| 484 | */ |
| 485 | @VisibleForTesting |
| 486 | void closeControls(View v, boolean save) { |
| 487 | int[] parentLoc = new int[2]; |
| 488 | int[] targetLoc = new int[2]; |
| 489 | mGutsContainer.getLocationOnScreen(parentLoc); |
| 490 | v.getLocationOnScreen(targetLoc); |
| 491 | final int centerX = v.getWidth() / 2; |
| 492 | final int centerY = v.getHeight() / 2; |
| 493 | final int x = targetLoc[0] - parentLoc[0] + centerX; |
| 494 | final int y = targetLoc[1] - parentLoc[1] + centerY; |
| 495 | mGutsContainer.closeControls(x, y, save, false /* force */); |
| 496 | } |
| 497 | |
| 498 | @Override |
| 499 | public void setGutsParent(NotificationGuts guts) { |
| 500 | mGutsContainer = guts; |
| 501 | } |
| 502 | |
| 503 | @Override |
| 504 | public boolean willBeRemoved() { |
| 505 | return false; |
| 506 | } |
| 507 | |
| 508 | @Override |
| 509 | public boolean shouldBeSaved() { |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 510 | return mSelectedAction == ACTION_FAVORITE || mSelectedAction == ACTION_MUTE; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 511 | } |
| 512 | |
| 513 | @Override |
| 514 | public View getContentView() { |
| 515 | return this; |
| 516 | } |
| 517 | |
| 518 | @Override |
| 519 | public boolean handleCloseControls(boolean save, boolean force) { |
| 520 | if (save && mSelectedAction > -1) { |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 521 | updateChannel(); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 522 | } |
| 523 | return false; |
| 524 | } |
| 525 | |
| 526 | @Override |
| 527 | public int getActualHeight() { |
| 528 | return getHeight(); |
| 529 | } |
| 530 | |
| 531 | @VisibleForTesting |
| 532 | public boolean isAnimating() { |
| 533 | return false; |
| 534 | } |
| 535 | |
Julia Reynolds | e6fed50 | 2020-02-07 14:41:02 -0500 | [diff] [blame] | 536 | class UpdateChannelRunnable implements Runnable { |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 537 | |
| 538 | private final INotificationManager mINotificationManager; |
| 539 | private final String mAppPkg; |
| 540 | private final int mAppUid; |
| 541 | private NotificationChannel mChannelToUpdate; |
| 542 | private final @Action int mAction; |
| 543 | |
| 544 | public UpdateChannelRunnable(INotificationManager notificationManager, |
| 545 | String packageName, int appUid, @Action int action, |
| 546 | @NonNull NotificationChannel channelToUpdate) { |
| 547 | mINotificationManager = notificationManager; |
| 548 | mAppPkg = packageName; |
| 549 | mAppUid = appUid; |
| 550 | mChannelToUpdate = channelToUpdate; |
| 551 | mAction = action; |
| 552 | } |
| 553 | |
| 554 | @Override |
| 555 | public void run() { |
| 556 | try { |
| 557 | switch (mAction) { |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 558 | case ACTION_FAVORITE: |
Julia Reynolds | 24edc00 | 2020-01-29 16:35:32 -0500 | [diff] [blame] | 559 | mChannelToUpdate.setImportantConversation( |
| 560 | !mChannelToUpdate.isImportantConversation()); |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 561 | if (mChannelToUpdate.isImportantConversation()) { |
Julia Reynolds | 908201e | 2020-02-17 21:53:49 -0500 | [diff] [blame] | 562 | mChannelToUpdate.setAllowBubbles(true); |
Mady Mellor | a92268c | 2020-03-09 17:25:08 -0700 | [diff] [blame] | 563 | int currentPref = |
| 564 | mINotificationManager.getBubblePreferenceForPackage( |
| 565 | mAppPkg, mAppUid); |
| 566 | if (currentPref == BUBBLE_PREFERENCE_NONE) { |
| 567 | mINotificationManager.setBubblesAllowed(mAppPkg, mAppUid, |
| 568 | BUBBLE_PREFERENCE_SELECTED); |
| 569 | } |
Julia Reynolds | 908201e | 2020-02-17 21:53:49 -0500 | [diff] [blame] | 570 | } |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 571 | mChannelToUpdate.setImportance(Math.max( |
| 572 | mChannelToUpdate.getOriginalImportance(), IMPORTANCE_DEFAULT)); |
| 573 | break; |
| 574 | case ACTION_DEFAULT: |
| 575 | mChannelToUpdate.setImportance(Math.max( |
| 576 | mChannelToUpdate.getOriginalImportance(), IMPORTANCE_DEFAULT)); |
| 577 | if (mChannelToUpdate.isImportantConversation()) { |
| 578 | mChannelToUpdate.setImportantConversation(false); |
| 579 | mChannelToUpdate.setAllowBubbles(false); |
| 580 | } |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 581 | break; |
| 582 | case ACTION_MUTE: |
| 583 | if (mChannelToUpdate.getImportance() == IMPORTANCE_UNSPECIFIED |
| 584 | || mChannelToUpdate.getImportance() >= IMPORTANCE_DEFAULT) { |
| 585 | mChannelToUpdate.setImportance(IMPORTANCE_LOW); |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 586 | } |
| 587 | if (mChannelToUpdate.isImportantConversation()) { |
| 588 | mChannelToUpdate.setImportantConversation(false); |
| 589 | mChannelToUpdate.setAllowBubbles(false); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 590 | } |
| 591 | break; |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 592 | } |
| 593 | |
Julia Reynolds | a856e49 | 2020-03-18 17:30:06 -0400 | [diff] [blame] | 594 | mINotificationManager.updateNotificationChannelForPackage( |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 595 | mAppPkg, mAppUid, mChannelToUpdate); |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 596 | } catch (RemoteException e) { |
| 597 | Log.e(TAG, "Unable to update notification channel", e); |
| 598 | } |
| 599 | } |
| 600 | } |
Julia Reynolds | 12ba4cf | 2020-01-10 16:01:38 -0500 | [diff] [blame] | 601 | } |