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