blob: a27199370b163e4e541104b9617428cc116074ee [file] [log] [blame]
Julia Reynolds12ba4cf2020-01-10 16:01:38 -05001/*
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
17package com.android.systemui.statusbar.notification.row;
18
19import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
Mady Mellora92268c2020-03-09 17:25:08 -070020import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
21import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050022import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
23import static android.app.NotificationManager.IMPORTANCE_LOW;
24import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050025
Julia Reynoldsa856e492020-03-18 17:30:06 -040026import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
27
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050028import static java.lang.annotation.RetentionPolicy.SOURCE;
29
30import android.annotation.IntDef;
31import android.annotation.NonNull;
32import android.app.INotificationManager;
33import android.app.Notification;
34import android.app.NotificationChannel;
35import android.app.NotificationChannelGroup;
36import android.content.Context;
37import android.content.Intent;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050038import android.content.pm.ApplicationInfo;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050039import android.content.pm.PackageManager;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050040import android.content.pm.ShortcutInfo;
41import android.content.pm.ShortcutManager;
42import android.graphics.drawable.Icon;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050043import android.os.Handler;
44import android.os.Parcelable;
45import android.os.RemoteException;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050046import android.service.notification.StatusBarNotification;
47import android.text.TextUtils;
Julia Reynoldsa856e492020-03-18 17:30:06 -040048import android.transition.ChangeBounds;
49import android.transition.Fade;
50import android.transition.TransitionManager;
51import android.transition.TransitionSet;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050052import android.util.AttributeSet;
53import android.util.Log;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050054import android.view.View;
55import android.view.accessibility.AccessibilityEvent;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050056import android.widget.ImageView;
57import android.widget.LinearLayout;
58import android.widget.TextView;
59
60import com.android.internal.annotations.VisibleForTesting;
Julia Reynolds01c9da42020-02-14 14:17:58 -050061import com.android.settingslib.notification.ConversationIconFactory;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050062import com.android.systemui.Dependency;
63import com.android.systemui.R;
Mady Mellor9adfe6a2020-03-30 17:23:26 -070064import com.android.systemui.statusbar.notification.NotificationChannelHelper;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050065import com.android.systemui.statusbar.notification.VisualStabilityManager;
66import com.android.systemui.statusbar.notification.collection.NotificationEntry;
67
68import java.lang.annotation.Retention;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050069import java.util.List;
70
71/**
72 * The guts of a conversation notification revealed when performing a long press.
73 */
74public class NotificationConversationInfo extends LinearLayout implements
75 NotificationGuts.GutsContent {
76 private static final String TAG = "ConversationGuts";
77
78
79 private INotificationManager mINotificationManager;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050080 ShortcutManager mShortcutManager;
81 private PackageManager mPm;
82 private VisualStabilityManager mVisualStabilityManager;
Julia Reynolds01c9da42020-02-14 14:17:58 -050083 private ConversationIconFactory mIconFactory;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050084
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 Reynolds12ba4cf2020-01-10 16:01:38 -050092 private StatusBarNotification mSbn;
93 private boolean mIsDeviceProvisioned;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050094
Julia Reynoldsa856e492020-03-18 17:30:06 -040095 private TextView mPriorityDescriptionView;
96 private TextView mDefaultDescriptionView;
97 private TextView mSilentDescriptionView;
Julia Reynoldse6fed502020-02-07 14:41:02 -050098 private @Action int mSelectedAction = -1;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -050099
100 private OnSnoozeClickListener mOnSnoozeClickListener;
101 private OnSettingsClickListener mOnSettingsClickListener;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500102 private NotificationGuts mGutsContainer;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500103
104 @VisibleForTesting
105 boolean mSkipPost = false;
106
Julia Reynoldse6fed502020-02-07 14:41:02 -0500107 @Retention(SOURCE)
Julia Reynoldsa856e492020-03-18 17:30:06 -0400108 @IntDef({ACTION_DEFAULT, ACTION_HOME, ACTION_FAVORITE, ACTION_SNOOZE, ACTION_MUTE,
109 ACTION_SETTINGS})
Julia Reynoldse6fed502020-02-07 14:41:02 -0500110 private @interface Action {}
Julia Reynoldsa856e492020-03-18 17:30:06 -0400111 static final int ACTION_DEFAULT = 0;
Julia Reynoldse6fed502020-02-07 14:41:02 -0500112 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 Reynoldse6fed502020-02-07 14:41:02 -0500117
Julia Reynoldsa856e492020-03-18 17:30:06 -0400118 // TODO: b/152050825
119 /*
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500120 private OnClickListener mOnHomeClick = v -> {
121 mSelectedAction = ACTION_HOME;
122 mShortcutManager.requestPinShortcut(mShortcutInfo, null);
Julia Reynoldse6fed502020-02-07 14:41:02 -0500123 mShadeController.animateCollapsePanels();
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500124 closeControls(v, true);
125 };
126
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500127 private OnClickListener mOnSnoozeClick = v -> {
128 mSelectedAction = ACTION_SNOOZE;
129 mOnSnoozeClickListener.onClick(v, 1);
130 closeControls(v, true);
131 };
Julia Reynoldsa856e492020-03-18 17:30:06 -0400132 */
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 Reynolds12ba4cf2020-01-10 16:01:38 -0500143
144 private OnClickListener mOnMuteClick = v -> {
Julia Reynoldse6fed502020-02-07 14:41:02 -0500145 mSelectedAction = ACTION_MUTE;
Julia Reynoldsa856e492020-03-18 17:30:06 -0400146 updateToggleActions(mSelectedAction, true);
147 };
148
149 private OnClickListener mOnDone = v -> {
150 closeControls(v, true);
Julia Reynoldsdcd70d62020-01-15 10:33:43 -0500151 };
152
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500153 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 Reynolds12ba4cf2020-01-10 16:01:38 -0500171 PackageManager pm,
172 INotificationManager iNotificationManager,
173 VisualStabilityManager visualStabilityManager,
174 String pkg,
175 NotificationChannel notificationChannel,
176 NotificationEntry entry,
177 OnSettingsClickListener onSettingsClick,
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500178 OnSnoozeClickListener onSnoozeClickListener,
Julia Reynolds01c9da42020-02-14 14:17:58 -0500179 ConversationIconFactory conversationIconFactory,
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500180 boolean isDeviceProvisioned) {
181 mSelectedAction = -1;
182 mINotificationManager = iNotificationManager;
183 mVisualStabilityManager = visualStabilityManager;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500184 mPackageName = pkg;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500185 mSbn = entry.getSbn();
186 mPm = pm;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500187 mAppName = mPackageName;
188 mOnSettingsClickListener = onSettingsClick;
189 mNotificationChannel = notificationChannel;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500190 mAppUid = mSbn.getUid();
191 mDelegatePkg = mSbn.getOpPkg();
192 mIsDeviceProvisioned = isDeviceProvisioned;
193 mOnSnoozeClickListener = onSnoozeClickListener;
Julia Reynolds01c9da42020-02-14 14:17:58 -0500194 mIconFactory = conversationIconFactory;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500195
196 mShortcutManager = shortcutManager;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500197 mConversationId = mNotificationChannel.getConversationId();
198 if (TextUtils.isEmpty(mNotificationChannel.getConversationId())) {
Julia Reynolds7c267522020-01-16 11:26:41 -0500199 mConversationId = mSbn.getShortcutId(mContext);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500200 }
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500201 if (TextUtils.isEmpty(mConversationId)) {
Julia Reynolds7c267522020-01-16 11:26:41 -0500202 throw new IllegalArgumentException("Does not have required information");
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500203 }
Julia Reynolds138111f2020-02-26 11:17:39 -0500204 mShortcutInfo = entry.getRanking().getShortcutInfo();
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500205
Mady Mellor9adfe6a2020-03-30 17:23:26 -0700206 mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded(
207 getContext(), mINotificationManager, entry, mNotificationChannel);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500208
209 bindHeader();
210 bindActions();
211
Julia Reynoldsa856e492020-03-18 17:30:06 -0400212 View done = findViewById(R.id.done);
213 done.setOnClickListener(mOnDone);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500214 }
215
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500216 private void bindActions() {
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500217
Julia Reynoldsa856e492020-03-18 17:30:06 -0400218 // TODO: b/152050825
219 /*
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500220 Button home = findViewById(R.id.home);
221 home.setOnClickListener(mOnHomeClick);
Julia Reynoldse6fed502020-02-07 14:41:02 -0500222 home.setVisibility(mShortcutInfo != null
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500223 && mShortcutManager.isRequestPinShortcutSupported()
224 ? VISIBLE : GONE);
225
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500226 Button snooze = findViewById(R.id.snooze);
227 snooze.setOnClickListener(mOnSnoozeClick);
Julia Reynoldsa856e492020-03-18 17:30:06 -0400228 */
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500229
Julia Reynoldsa856e492020-03-18 17:30:06 -0400230 findViewById(R.id.priority).setOnClickListener(mOnFavoriteClick);
231 findViewById(R.id.default_behavior).setOnClickListener(mOnDefaultClick);
232 findViewById(R.id.silence).setOnClickListener(mOnMuteClick);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500233
Julia Reynoldse6fed502020-02-07 14:41:02 -0500234 final View settingsButton = findViewById(R.id.info);
235 settingsButton.setOnClickListener(getSettingsOnClickListener());
236 settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
237
Julia Reynoldsa856e492020-03-18 17:30:06 -0400238 updateToggleActions(getSelectedAction(), false);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500239 }
240
241 private void bindHeader() {
242 bindConversationDetails();
243
244 // Delegate
245 bindDelegate();
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500246 }
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 Reynoldsf2acd602020-01-21 16:01:25 -0500263 // TODO: bring back when channel name does not include name
264 // bindName();
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500265 bindPackage();
Julia Reynoldsa856e492020-03-18 17:30:06 -0400266 bindIcon(mNotificationChannel.isImportantConversation());
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500267
268 }
269
Julia Reynoldsa856e492020-03-18 17:30:06 -0400270 private void bindIcon(boolean important) {
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500271 ImageView image = findViewById(R.id.conversation_icon);
272 if (mShortcutInfo != null) {
Dan Sandlerb11f2de2020-02-19 13:18:24 -0500273 image.setImageDrawable(mIconFactory.getConversationDrawable(
274 mShortcutInfo, mPackageName, mAppUid,
Julia Reynoldsa856e492020-03-18 17:30:06 -0400275 important));
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500276 } else {
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500277 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 Reynolds12ba4cf2020-01-10 16:01:38 -0500299 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 Reynolds12ba4cf2020-01-10 16:01:38 -0500318
319 if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
320 // this notification was posted by a delegate!
321 delegateView.setVisibility(View.VISIBLE);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500322 } else {
323 delegateView.setVisibility(View.GONE);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500324 }
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 Reynoldsa856e492020-03-18 17:30:06 -0400364 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 Reynolds12ba4cf2020-01-10 16:01:38 -0500373 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 Reynoldsa856e492020-03-18 17:30:06 -0400392 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 Reynolds12ba4cf2020-01-10 16:01:38 -0500406 }
Julia Reynoldse6fed502020-02-07 14:41:02 -0500407
Julia Reynoldsa856e492020-03-18 17:30:06 -0400408 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 Reynolds12ba4cf2020-01-10 16:01:38 -0500448 }
Dan Sandlerb11f2de2020-02-19 13:18:24 -0500449
Julia Reynoldsa856e492020-03-18 17:30:06 -0400450 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 Sandlerb11f2de2020-02-19 13:18:24 -0500456 // update icon in case importance has changed
Julia Reynoldsa856e492020-03-18 17:30:06 -0400457 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 Reynoldse6fed502020-02-07 14:41:02 -0500470 }
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 Reynolds12ba4cf2020-01-10 16:01:38 -0500477 }
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 Reynoldsa856e492020-03-18 17:30:06 -0400510 return mSelectedAction == ACTION_FAVORITE || mSelectedAction == ACTION_MUTE;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500511 }
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 Reynoldse6fed502020-02-07 14:41:02 -0500521 updateChannel();
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500522 }
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 Reynoldse6fed502020-02-07 14:41:02 -0500536 class UpdateChannelRunnable implements Runnable {
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500537
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 Reynolds12ba4cf2020-01-10 16:01:38 -0500558 case ACTION_FAVORITE:
Julia Reynolds24edc002020-01-29 16:35:32 -0500559 mChannelToUpdate.setImportantConversation(
560 !mChannelToUpdate.isImportantConversation());
Julia Reynoldsa856e492020-03-18 17:30:06 -0400561 if (mChannelToUpdate.isImportantConversation()) {
Julia Reynolds908201e2020-02-17 21:53:49 -0500562 mChannelToUpdate.setAllowBubbles(true);
Mady Mellora92268c2020-03-09 17:25:08 -0700563 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 Reynolds908201e2020-02-17 21:53:49 -0500570 }
Julia Reynoldsa856e492020-03-18 17:30:06 -0400571 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 Reynolds12ba4cf2020-01-10 16:01:38 -0500581 break;
582 case ACTION_MUTE:
583 if (mChannelToUpdate.getImportance() == IMPORTANCE_UNSPECIFIED
584 || mChannelToUpdate.getImportance() >= IMPORTANCE_DEFAULT) {
585 mChannelToUpdate.setImportance(IMPORTANCE_LOW);
Julia Reynoldsa856e492020-03-18 17:30:06 -0400586 }
587 if (mChannelToUpdate.isImportantConversation()) {
588 mChannelToUpdate.setImportantConversation(false);
589 mChannelToUpdate.setAllowBubbles(false);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500590 }
591 break;
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500592 }
593
Julia Reynoldsa856e492020-03-18 17:30:06 -0400594 mINotificationManager.updateNotificationChannelForPackage(
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500595 mAppPkg, mAppUid, mChannelToUpdate);
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500596 } catch (RemoteException e) {
597 Log.e(TAG, "Unable to update notification channel", e);
598 }
599 }
600 }
Julia Reynolds12ba4cf2020-01-10 16:01:38 -0500601}