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.NotificationManager.BUBBLE_PREFERENCE_ALL; 20 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; 21 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; 22 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 23 import static android.app.NotificationManager.IMPORTANCE_LOW; 24 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; 25 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE; 26 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT; 27 28 import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN; 29 30 import static java.lang.annotation.RetentionPolicy.SOURCE; 31 32 import android.annotation.IntDef; 33 import android.annotation.NonNull; 34 import android.annotation.Nullable; 35 import android.app.INotificationManager; 36 import android.app.Notification; 37 import android.app.NotificationChannel; 38 import android.app.NotificationChannelGroup; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.pm.ApplicationInfo; 42 import android.content.pm.PackageManager; 43 import android.content.pm.ShortcutInfo; 44 import android.content.pm.ShortcutManager; 45 import android.content.res.TypedArray; 46 import android.graphics.drawable.Drawable; 47 import android.os.Bundle; 48 import android.os.Handler; 49 import android.os.RemoteException; 50 import android.os.UserHandle; 51 import android.service.notification.StatusBarNotification; 52 import android.text.TextUtils; 53 import android.transition.ChangeBounds; 54 import android.transition.Fade; 55 import android.transition.TransitionManager; 56 import android.transition.TransitionSet; 57 import android.util.AttributeSet; 58 import android.util.Log; 59 import android.view.View; 60 import android.view.accessibility.AccessibilityEvent; 61 import android.widget.ImageView; 62 import android.widget.LinearLayout; 63 import android.widget.TextView; 64 65 import com.android.internal.annotations.VisibleForTesting; 66 import com.android.settingslib.notification.ConversationIconFactory; 67 import com.android.systemui.R; 68 import com.android.systemui.dagger.qualifiers.Background; 69 import com.android.systemui.dagger.qualifiers.Main; 70 import com.android.systemui.people.widget.PeopleSpaceWidgetManager; 71 import com.android.systemui.statusbar.notification.NotificationChannelHelper; 72 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 73 import com.android.systemui.statusbar.notification.stack.StackStateAnimator; 74 import com.android.systemui.statusbar.phone.ShadeController; 75 import com.android.systemui.wmshell.BubblesManager; 76 77 import java.lang.annotation.Retention; 78 import java.util.Optional; 79 80 /** 81 * The guts of a conversation notification revealed when performing a long press. 82 */ 83 public class NotificationConversationInfo extends LinearLayout implements 84 NotificationGuts.GutsContent { 85 private static final String TAG = "ConversationGuts"; 86 87 private INotificationManager mINotificationManager; 88 private ShortcutManager mShortcutManager; 89 private PackageManager mPm; 90 private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager; 91 private ConversationIconFactory mIconFactory; 92 private OnUserInteractionCallback mOnUserInteractionCallback; 93 private Handler mMainHandler; 94 private Handler mBgHandler; 95 private Optional<BubblesManager> mBubblesManagerOptional; 96 private ShadeController mShadeController; 97 private String mPackageName; 98 private String mAppName; 99 private int mAppUid; 100 private String mDelegatePkg; 101 private NotificationChannel mNotificationChannel; 102 private ShortcutInfo mShortcutInfo; 103 private NotificationEntry mEntry; 104 private StatusBarNotification mSbn; 105 @Nullable private Notification.BubbleMetadata mBubbleMetadata; 106 private Context mUserContext; 107 private boolean mIsDeviceProvisioned; 108 private int mAppBubble; 109 110 private TextView mPriorityDescriptionView; 111 private TextView mDefaultDescriptionView; 112 private TextView mSilentDescriptionView; 113 114 private @Action int mSelectedAction = -1; 115 private boolean mPressedApply; 116 117 private OnSettingsClickListener mOnSettingsClickListener; 118 private NotificationGuts mGutsContainer; 119 private OnConversationSettingsClickListener mOnConversationSettingsClickListener; 120 121 @VisibleForTesting 122 boolean mSkipPost = false; 123 private int mActualHeight; 124 125 @Retention(SOURCE) 126 @IntDef({ACTION_DEFAULT, ACTION_HOME, ACTION_FAVORITE, ACTION_SNOOZE, ACTION_MUTE, 127 ACTION_SETTINGS}) 128 private @interface Action {} 129 static final int ACTION_DEFAULT = 0; 130 static final int ACTION_HOME = 1; 131 static final int ACTION_FAVORITE = 2; 132 static final int ACTION_SNOOZE = 3; 133 static final int ACTION_MUTE = 4; 134 static final int ACTION_SETTINGS = 5; 135 136 private OnClickListener mOnFavoriteClick = v -> { 137 setSelectedAction(ACTION_FAVORITE); 138 updateToggleActions(mSelectedAction, true); 139 }; 140 141 private OnClickListener mOnDefaultClick = v -> { 142 setSelectedAction(ACTION_DEFAULT); 143 updateToggleActions(mSelectedAction, true); 144 }; 145 146 private OnClickListener mOnMuteClick = v -> { 147 setSelectedAction(ACTION_MUTE); 148 updateToggleActions(mSelectedAction, true); 149 }; 150 151 private OnClickListener mOnDone = v -> { 152 mPressedApply = true; 153 154 // If the user selected Priority and the previous selection was not priority, show a 155 // People Tile add request. 156 if (mSelectedAction == ACTION_FAVORITE && getPriority() != mSelectedAction) { 157 mShadeController.animateCollapsePanels(); 158 mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle()); 159 } 160 mGutsContainer.closeControls(v, true); 161 }; 162 NotificationConversationInfo(Context context, AttributeSet attrs)163 public NotificationConversationInfo(Context context, AttributeSet attrs) { 164 super(context, attrs); 165 } 166 167 public interface OnSettingsClickListener { onClick(View v, NotificationChannel channel, int appUid)168 void onClick(View v, NotificationChannel channel, int appUid); 169 } 170 171 public interface OnConversationSettingsClickListener { onClick()172 void onClick(); 173 } 174 175 public interface OnAppSettingsClickListener { onClick(View v, Intent intent)176 void onClick(View v, Intent intent); 177 } 178 179 @VisibleForTesting setSelectedAction(int selectedAction)180 void setSelectedAction(int selectedAction) { 181 if (mSelectedAction == selectedAction) { 182 return; 183 } 184 185 mSelectedAction = selectedAction; 186 } 187 bindNotification( @ction int selectedAction, ShortcutManager shortcutManager, PackageManager pm, PeopleSpaceWidgetManager peopleSpaceWidgetManager, INotificationManager iNotificationManager, OnUserInteractionCallback onUserInteractionCallback, String pkg, NotificationChannel notificationChannel, NotificationEntry entry, Notification.BubbleMetadata bubbleMetadata, OnSettingsClickListener onSettingsClick, ConversationIconFactory conversationIconFactory, Context userContext, boolean isDeviceProvisioned, @Main Handler mainHandler, @Background Handler bgHandler, OnConversationSettingsClickListener onConversationSettingsClickListener, Optional<BubblesManager> bubblesManagerOptional, ShadeController shadeController)188 public void bindNotification( 189 @Action int selectedAction, 190 ShortcutManager shortcutManager, 191 PackageManager pm, 192 PeopleSpaceWidgetManager peopleSpaceWidgetManager, 193 INotificationManager iNotificationManager, 194 OnUserInteractionCallback onUserInteractionCallback, 195 String pkg, 196 NotificationChannel notificationChannel, 197 NotificationEntry entry, 198 Notification.BubbleMetadata bubbleMetadata, 199 OnSettingsClickListener onSettingsClick, 200 ConversationIconFactory conversationIconFactory, 201 Context userContext, 202 boolean isDeviceProvisioned, 203 @Main Handler mainHandler, 204 @Background Handler bgHandler, 205 OnConversationSettingsClickListener onConversationSettingsClickListener, 206 Optional<BubblesManager> bubblesManagerOptional, 207 ShadeController shadeController) { 208 mPressedApply = false; 209 mSelectedAction = selectedAction; 210 mINotificationManager = iNotificationManager; 211 mPeopleSpaceWidgetManager = peopleSpaceWidgetManager; 212 mOnUserInteractionCallback = onUserInteractionCallback; 213 mPackageName = pkg; 214 mEntry = entry; 215 mSbn = entry.getSbn(); 216 mPm = pm; 217 mAppName = mPackageName; 218 mOnSettingsClickListener = onSettingsClick; 219 mNotificationChannel = notificationChannel; 220 mAppUid = mSbn.getUid(); 221 mDelegatePkg = mSbn.getOpPkg(); 222 mIsDeviceProvisioned = isDeviceProvisioned; 223 mOnConversationSettingsClickListener = onConversationSettingsClickListener; 224 mIconFactory = conversationIconFactory; 225 mUserContext = userContext; 226 mBubbleMetadata = bubbleMetadata; 227 mBubblesManagerOptional = bubblesManagerOptional; 228 mShadeController = shadeController; 229 mMainHandler = mainHandler; 230 mBgHandler = bgHandler; 231 mShortcutManager = shortcutManager; 232 mShortcutInfo = entry.getRanking().getConversationShortcutInfo(); 233 if (mShortcutInfo == null) { 234 throw new IllegalArgumentException("Does not have required information"); 235 } 236 237 mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded( 238 getContext(), mINotificationManager, entry, mNotificationChannel); 239 240 try { 241 mAppBubble = mINotificationManager.getBubblePreferenceForPackage(mPackageName, mAppUid); 242 } catch (RemoteException e) { 243 Log.e(TAG, "can't reach OS", e); 244 mAppBubble = BUBBLE_PREFERENCE_SELECTED; 245 } 246 247 bindHeader(); 248 bindActions(); 249 250 View done = findViewById(R.id.done); 251 done.setOnClickListener(mOnDone); 252 done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate()); 253 } 254 bindActions()255 private void bindActions() { 256 257 // TODO: b/152050825 258 /* 259 Button home = findViewById(R.id.home); 260 home.setOnClickListener(mOnHomeClick); 261 home.setVisibility(mShortcutInfo != null 262 && mShortcutManager.isRequestPinShortcutSupported() 263 ? VISIBLE : GONE); 264 265 Button snooze = findViewById(R.id.snooze); 266 snooze.setOnClickListener(mOnSnoozeClick); 267 */ 268 269 if (mAppBubble == BUBBLE_PREFERENCE_ALL) { 270 ((TextView) findViewById(R.id.default_summary)).setText(getResources().getString( 271 R.string.notification_channel_summary_default_with_bubbles, mAppName)); 272 } 273 274 findViewById(R.id.priority).setOnClickListener(mOnFavoriteClick); 275 findViewById(R.id.default_behavior).setOnClickListener(mOnDefaultClick); 276 findViewById(R.id.silence).setOnClickListener(mOnMuteClick); 277 278 final View settingsButton = findViewById(R.id.info); 279 settingsButton.setOnClickListener(getSettingsOnClickListener()); 280 settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE); 281 282 updateToggleActions(mSelectedAction == -1 ? getPriority() : mSelectedAction, 283 false); 284 } 285 bindHeader()286 private void bindHeader() { 287 bindConversationDetails(); 288 289 // Delegate 290 bindDelegate(); 291 } 292 getSettingsOnClickListener()293 private OnClickListener getSettingsOnClickListener() { 294 if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) { 295 final int appUidF = mAppUid; 296 return ((View view) -> { 297 mOnSettingsClickListener.onClick(view, mNotificationChannel, appUidF); 298 }); 299 } 300 return null; 301 } 302 bindConversationDetails()303 private void bindConversationDetails() { 304 final TextView channelName = findViewById(R.id.parent_channel_name); 305 channelName.setText(mNotificationChannel.getName()); 306 307 bindGroup(); 308 // TODO: bring back when channel name does not include name 309 // bindName(); 310 bindPackage(); 311 bindIcon(mNotificationChannel.isImportantConversation()); 312 313 mPriorityDescriptionView = findViewById(R.id.priority_summary); 314 if (willShowAsBubble() && willBypassDnd()) { 315 mPriorityDescriptionView.setText(R.string.notification_channel_summary_priority_all); 316 } else if (willShowAsBubble()) { 317 mPriorityDescriptionView.setText(R.string.notification_channel_summary_priority_bubble); 318 } else if (willBypassDnd()) { 319 mPriorityDescriptionView.setText(R.string.notification_channel_summary_priority_dnd); 320 } else { 321 mPriorityDescriptionView.setText( 322 R.string.notification_channel_summary_priority_baseline); 323 } 324 } 325 bindIcon(boolean important)326 private void bindIcon(boolean important) { 327 Drawable person = mIconFactory.getBaseIconDrawable(mShortcutInfo); 328 if (person == null) { 329 person = mContext.getDrawable(R.drawable.ic_person).mutate(); 330 TypedArray ta = mContext.obtainStyledAttributes(new int[]{android.R.attr.colorAccent}); 331 int colorAccent = ta.getColor(0, 0); 332 ta.recycle(); 333 person.setTint(colorAccent); 334 } 335 ImageView image = findViewById(R.id.conversation_icon); 336 image.setImageDrawable(person); 337 338 ImageView app = findViewById(R.id.conversation_icon_badge_icon); 339 app.setImageDrawable(mIconFactory.getAppBadge( 340 mPackageName, UserHandle.getUserId(mSbn.getUid()))); 341 342 findViewById(R.id.conversation_icon_badge_ring).setVisibility(important ? VISIBLE : GONE); 343 } 344 bindPackage()345 private void bindPackage() { 346 ApplicationInfo info; 347 try { 348 info = mPm.getApplicationInfo( 349 mPackageName, 350 PackageManager.MATCH_UNINSTALLED_PACKAGES 351 | PackageManager.MATCH_DISABLED_COMPONENTS 352 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 353 | PackageManager.MATCH_DIRECT_BOOT_AWARE); 354 if (info != null) { 355 mAppName = String.valueOf(mPm.getApplicationLabel(info)); 356 } 357 } catch (PackageManager.NameNotFoundException e) { 358 } 359 ((TextView) findViewById(R.id.pkg_name)).setText(mAppName); 360 } 361 bindDelegate()362 private void bindDelegate() { 363 TextView delegateView = findViewById(R.id.delegate_name); 364 365 if (!TextUtils.equals(mPackageName, mDelegatePkg)) { 366 // this notification was posted by a delegate! 367 delegateView.setVisibility(View.VISIBLE); 368 } else { 369 delegateView.setVisibility(View.GONE); 370 } 371 } 372 bindGroup()373 private void bindGroup() { 374 // Set group information if this channel has an associated group. 375 CharSequence groupName = null; 376 if (mNotificationChannel != null && mNotificationChannel.getGroup() != null) { 377 try { 378 final NotificationChannelGroup notificationChannelGroup = 379 mINotificationManager.getNotificationChannelGroupForPackage( 380 mNotificationChannel.getGroup(), mPackageName, mAppUid); 381 if (notificationChannelGroup != null) { 382 groupName = notificationChannelGroup.getName(); 383 } 384 } catch (RemoteException e) { 385 } 386 } 387 TextView groupNameView = findViewById(R.id.group_name); 388 if (groupName != null) { 389 groupNameView.setText(groupName); 390 groupNameView.setVisibility(VISIBLE); 391 } else { 392 groupNameView.setVisibility(GONE); 393 } 394 } 395 396 @Override post(Runnable action)397 public boolean post(Runnable action) { 398 if (mSkipPost) { 399 action.run(); 400 return true; 401 } else { 402 return super.post(action); 403 } 404 } 405 406 @Override onFinishInflate()407 protected void onFinishInflate() { 408 super.onFinishInflate(); 409 410 mDefaultDescriptionView = findViewById(R.id.default_summary); 411 mSilentDescriptionView = findViewById(R.id.silence_summary); 412 } 413 414 @Override onFinishedClosing()415 public void onFinishedClosing() { 416 mSelectedAction = -1; 417 } 418 419 @Override needsFalsingProtection()420 public boolean needsFalsingProtection() { 421 return true; 422 } 423 424 @Override onInitializeAccessibilityEvent(AccessibilityEvent event)425 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 426 super.onInitializeAccessibilityEvent(event); 427 if (mGutsContainer != null && 428 event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { 429 if (mGutsContainer.isExposed()) { 430 event.getText().add(mContext.getString( 431 R.string.notification_channel_controls_opened_accessibility, mAppName)); 432 } else { 433 event.getText().add(mContext.getString( 434 R.string.notification_channel_controls_closed_accessibility, mAppName)); 435 } 436 } 437 } 438 updateToggleActions(int selectedAction, boolean userTriggered)439 private void updateToggleActions(int selectedAction, boolean userTriggered) { 440 if (userTriggered) { 441 TransitionSet transition = new TransitionSet(); 442 transition.setOrdering(TransitionSet.ORDERING_TOGETHER); 443 transition.addTransition(new Fade(Fade.OUT)) 444 .addTransition(new ChangeBounds()) 445 .addTransition( 446 new Fade(Fade.IN) 447 .setStartDelay(150) 448 .setDuration(200) 449 .setInterpolator(FAST_OUT_SLOW_IN)); 450 transition.setDuration(350); 451 transition.setInterpolator(FAST_OUT_SLOW_IN); 452 TransitionManager.beginDelayedTransition(this, transition); 453 } 454 455 View priority = findViewById(R.id.priority); 456 View defaultBehavior = findViewById(R.id.default_behavior); 457 View silence = findViewById(R.id.silence); 458 459 switch (selectedAction) { 460 case ACTION_FAVORITE: 461 mPriorityDescriptionView.setVisibility(VISIBLE); 462 mDefaultDescriptionView.setVisibility(GONE); 463 mSilentDescriptionView.setVisibility(GONE); 464 post(() -> { 465 priority.setSelected(true); 466 defaultBehavior.setSelected(false); 467 silence.setSelected(false); 468 }); 469 break; 470 471 case ACTION_MUTE: 472 mSilentDescriptionView.setVisibility(VISIBLE); 473 mDefaultDescriptionView.setVisibility(GONE); 474 mPriorityDescriptionView.setVisibility(GONE); 475 post(() -> { 476 priority.setSelected(false); 477 defaultBehavior.setSelected(false); 478 silence.setSelected(true); 479 }); 480 break; 481 482 case ACTION_DEFAULT: 483 mDefaultDescriptionView.setVisibility(VISIBLE); 484 mSilentDescriptionView.setVisibility(GONE); 485 mPriorityDescriptionView.setVisibility(GONE); 486 post(() -> { 487 priority.setSelected(false); 488 defaultBehavior.setSelected(true); 489 silence.setSelected(false); 490 }); 491 break; 492 493 default: 494 throw new IllegalArgumentException("Unrecognized behavior: " + mSelectedAction); 495 } 496 497 boolean isAChange = getPriority() != selectedAction; 498 TextView done = findViewById(R.id.done); 499 done.setText(isAChange 500 ? R.string.inline_ok_button 501 : R.string.inline_done_button); 502 503 // update icon in case importance has changed 504 bindIcon(selectedAction == ACTION_FAVORITE); 505 } 506 getSelectedAction()507 int getSelectedAction() { 508 return mSelectedAction; 509 } 510 getPriority()511 private int getPriority() { 512 if (mNotificationChannel.getImportance() <= IMPORTANCE_LOW 513 && mNotificationChannel.getImportance() > IMPORTANCE_UNSPECIFIED) { 514 return ACTION_MUTE; 515 } else { 516 if (mNotificationChannel.isImportantConversation()) { 517 return ACTION_FAVORITE; 518 } 519 } 520 return ACTION_DEFAULT; 521 } 522 updateChannel()523 private void updateChannel() { 524 mBgHandler.post( 525 new UpdateChannelRunnable(mINotificationManager, mPackageName, 526 mAppUid, mSelectedAction, mNotificationChannel)); 527 mEntry.markForUserTriggeredMovement(true); 528 mMainHandler.postDelayed( 529 () -> mOnUserInteractionCallback.onImportanceChanged(mEntry), 530 StackStateAnimator.ANIMATION_DURATION_STANDARD); 531 } 532 willBypassDnd()533 private boolean willBypassDnd() { 534 boolean bypassesDnd = false; 535 try { 536 int allowedSenders = mINotificationManager 537 .getConsolidatedNotificationPolicy().priorityConversationSenders; 538 bypassesDnd = allowedSenders == CONVERSATION_SENDERS_IMPORTANT 539 || allowedSenders == CONVERSATION_SENDERS_ANYONE; 540 } catch (RemoteException e) { 541 Log.e(TAG, "Could not check conversation senders", e); 542 } 543 return bypassesDnd; 544 } 545 willShowAsBubble()546 private boolean willShowAsBubble() { 547 return mBubbleMetadata != null 548 && BubblesManager.areBubblesEnabled(mContext, mSbn.getUser()); 549 } 550 551 @Override setGutsParent(NotificationGuts guts)552 public void setGutsParent(NotificationGuts guts) { 553 mGutsContainer = guts; 554 } 555 556 @Override willBeRemoved()557 public boolean willBeRemoved() { 558 return false; 559 } 560 561 @Override shouldBeSaved()562 public boolean shouldBeSaved() { 563 return mPressedApply; 564 } 565 566 @Override getContentView()567 public View getContentView() { 568 return this; 569 } 570 571 @Override handleCloseControls(boolean save, boolean force)572 public boolean handleCloseControls(boolean save, boolean force) { 573 if (save && mSelectedAction > -1) { 574 updateChannel(); 575 } 576 return false; 577 } 578 579 @Override getActualHeight()580 public int getActualHeight() { 581 // Because we're animating the bounds, getHeight will return the small height at the 582 // beginning of the animation. Instead we'd want it to already return the end value 583 return mActualHeight; 584 } 585 586 @Override onLayout(boolean changed, int l, int t, int r, int b)587 protected void onLayout(boolean changed, int l, int t, int r, int b) { 588 super.onLayout(changed, l, t, r, b); 589 mActualHeight = getHeight(); 590 } 591 592 @VisibleForTesting isAnimating()593 public boolean isAnimating() { 594 return false; 595 } 596 597 class UpdateChannelRunnable implements Runnable { 598 599 private final INotificationManager mINotificationManager; 600 private final String mAppPkg; 601 private final int mAppUid; 602 private NotificationChannel mChannelToUpdate; 603 private final @Action int mAction; 604 UpdateChannelRunnable(INotificationManager notificationManager, String packageName, int appUid, @Action int action, @NonNull NotificationChannel channelToUpdate)605 public UpdateChannelRunnable(INotificationManager notificationManager, 606 String packageName, int appUid, @Action int action, 607 @NonNull NotificationChannel channelToUpdate) { 608 mINotificationManager = notificationManager; 609 mAppPkg = packageName; 610 mAppUid = appUid; 611 mChannelToUpdate = channelToUpdate; 612 mAction = action; 613 } 614 615 @Override run()616 public void run() { 617 try { 618 switch (mAction) { 619 case ACTION_FAVORITE: 620 mChannelToUpdate.setImportantConversation(true); 621 if (mChannelToUpdate.isImportantConversation()) { 622 mChannelToUpdate.setAllowBubbles(true); 623 if (mAppBubble == BUBBLE_PREFERENCE_NONE) { 624 mINotificationManager.setBubblesAllowed(mAppPkg, mAppUid, 625 BUBBLE_PREFERENCE_SELECTED); 626 } 627 if (mBubblesManagerOptional.isPresent()) { 628 post(() -> mBubblesManagerOptional.get() 629 .onUserSetImportantConversation(mEntry)); 630 } 631 } 632 mChannelToUpdate.setImportance(Math.max( 633 mChannelToUpdate.getOriginalImportance(), IMPORTANCE_DEFAULT)); 634 break; 635 case ACTION_DEFAULT: 636 mChannelToUpdate.setImportance(Math.max( 637 mChannelToUpdate.getOriginalImportance(), IMPORTANCE_DEFAULT)); 638 if (mChannelToUpdate.isImportantConversation()) { 639 mChannelToUpdate.setImportantConversation(false); 640 mChannelToUpdate.setAllowBubbles(false); 641 } 642 break; 643 case ACTION_MUTE: 644 if (mChannelToUpdate.getImportance() == IMPORTANCE_UNSPECIFIED 645 || mChannelToUpdate.getImportance() >= IMPORTANCE_DEFAULT) { 646 mChannelToUpdate.setImportance(IMPORTANCE_LOW); 647 } 648 if (mChannelToUpdate.isImportantConversation()) { 649 mChannelToUpdate.setImportantConversation(false); 650 mChannelToUpdate.setAllowBubbles(false); 651 } 652 break; 653 } 654 655 mINotificationManager.updateNotificationChannelForPackage( 656 mAppPkg, mAppUid, mChannelToUpdate); 657 } catch (RemoteException e) { 658 Log.e(TAG, "Unable to update notification channel", e); 659 } 660 } 661 } 662 } 663