Notification Bubble Button am: 9adfe6a20c am: bf4131708a
Change-Id: Iab279ae35352186d4acedc6bc9224f9f6251d93e
This commit is contained in:
@@ -77,7 +77,7 @@ interface IStatusBarService
|
||||
void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply,
|
||||
in int notificationLocation, boolean modifiedBeforeSending);
|
||||
void onNotificationSettingsViewed(String key);
|
||||
void onNotificationBubbleChanged(String key, boolean isBubble);
|
||||
void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
|
||||
void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed);
|
||||
void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
|
||||
void clearInlineReplyUriPermissions(String key);
|
||||
|
||||
@@ -20,16 +20,34 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/notification_action_list_margin_top"
|
||||
android:layout_gravity="bottom">
|
||||
<com.android.internal.widget.NotificationActionListLayout
|
||||
android:id="@+id/actions"
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_action_list_height"
|
||||
android:paddingEnd="12dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:visibility="gone"
|
||||
android:background="@color/notification_action_list_background_color"
|
||||
android:paddingEnd="12dp"
|
||||
>
|
||||
<!-- actions will be added here -->
|
||||
</com.android.internal.widget.NotificationActionListLayout>
|
||||
|
||||
<com.android.internal.widget.NotificationActionListLayout
|
||||
android:id="@+id/actions"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="@dimen/notification_action_list_height"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:visibility="gone"
|
||||
android:background="@color/notification_action_list_background_color"
|
||||
>
|
||||
<!-- actions will be added here -->
|
||||
</com.android.internal.widget.NotificationActionListLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/bubble_button"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:visibility="gone"
|
||||
android:scaleType="centerInside"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -3497,6 +3497,7 @@
|
||||
<java-symbol type="id" name="clip_children_set_tag" />
|
||||
<java-symbol type="id" name="clip_to_padding_tag" />
|
||||
<java-symbol type="id" name="clip_children_tag" />
|
||||
<java-symbol type="id" name="bubble_button" />
|
||||
<java-symbol type="dimen" name="messaging_avatar_size" />
|
||||
<java-symbol type="dimen" name="messaging_group_sending_progress_size" />
|
||||
<java-symbol type="dimen" name="messaging_image_rounding" />
|
||||
|
||||
@@ -14,16 +14,12 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,3c-4.97,0 -9,4.03 -9,9c0,1.39 0.32,2.69 0.88,3.86l1.53,-1.53C5.15,13.6 5,12.82 5,12c0,-3.86 3.14,-7 7,-7s7,3.14 7,7s-3.14,7 -7,7c-0.83,0 -1.62,-0.15 -2.35,-0.42l-1.53,1.53C9.3,20.67 10.61,21 12,21c4.97,0 9,-4.03 9,-9C21,7.03 16.97,3 12,3z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M12.99,15.99l2,0l0,-7l-7,0l0,2l3.59,0l-8.79,8.8l1.41,1.41l8.79,-8.79z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M22,12C22,12 22,12 22,12C22,12 22,12 22,12c0,0.56 -0.06,1.1 -0.15,1.64l-1.97,-0.33c0.15,-0.91 0.15,-1.84 -0.02,-2.75c-0.01,-0.03 -0.01,-0.07 -0.02,-0.1c-0.03,-0.18 -0.08,-0.36 -0.13,-0.54c-0.02,-0.08 -0.04,-0.16 -0.06,-0.24c-0.04,-0.14 -0.09,-0.27 -0.14,-0.41c-0.04,-0.12 -0.08,-0.24 -0.13,-0.35c-0.04,-0.09 -0.08,-0.18 -0.13,-0.27c-0.07,-0.15 -0.14,-0.3 -0.22,-0.45c-0.03,-0.05 -0.06,-0.09 -0.08,-0.14c-0.72,-1.26 -1.77,-2.31 -3.03,-3.03c-0.05,-0.03 -0.09,-0.06 -0.14,-0.08c-0.15,-0.08 -0.3,-0.15 -0.45,-0.22c-0.09,-0.04 -0.18,-0.09 -0.27,-0.13c-0.11,-0.05 -0.23,-0.09 -0.35,-0.13c-0.14,-0.05 -0.27,-0.1 -0.41,-0.14c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.18,-0.05 -0.36,-0.1 -0.54,-0.13c-0.03,-0.01 -0.07,-0.01 -0.1,-0.01c-0.95,-0.17 -1.93,-0.17 -2.88,0c-0.03,0.01 -0.07,0.01 -0.1,0.01c-0.18,0.04 -0.36,0.08 -0.54,0.13C9.85,4.3 9.77,4.32 9.69,4.34C9.55,4.38 9.42,4.44 9.28,4.49C9.17,4.53 9.05,4.57 8.93,4.61C8.84,4.65 8.75,4.7 8.66,4.74c-0.15,0.07 -0.3,0.14 -0.45,0.22C8.16,4.98 8.12,5.01 8.07,5.04C5.64,6.42 4,9.02 4,12c0,2.74 1.39,5.16 3.49,6.6c0.01,0.01 0.03,0.02 0.04,0.03c0.16,0.11 0.33,0.2 0.49,0.3c0.06,0.04 0.12,0.08 0.19,0.11c0.13,0.07 0.27,0.13 0.4,0.19c0.11,0.05 0.21,0.1 0.32,0.15c0.1,0.04 0.2,0.07 0.29,0.11c0.15,0.06 0.31,0.11 0.46,0.16c0.05,0.02 0.11,0.03 0.17,0.04c1.11,0.31 2.27,0.35 3.4,0.18l0.35,1.98c-0.54,0.09 -1.08,0.14 -1.62,0.14V22c-0.65,0 -1.28,-0.07 -1.9,-0.19c-0.01,0 -0.01,0 -0.02,0c-0.25,-0.05 -0.49,-0.11 -0.73,-0.18c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.19,-0.06 -0.37,-0.13 -0.55,-0.19c-0.13,-0.05 -0.26,-0.09 -0.39,-0.14c-0.13,-0.05 -0.25,-0.12 -0.38,-0.18c-0.18,-0.08 -0.35,-0.16 -0.53,-0.25c-0.07,-0.04 -0.14,-0.08 -0.21,-0.13c-0.22,-0.12 -0.43,-0.25 -0.64,-0.39c-0.01,-0.01 -0.02,-0.02 -0.04,-0.03c-0.51,-0.35 -1,-0.74 -1.45,-1.2l0,0C3.12,17.26 2,14.76 2,12c0,-2.76 1.12,-5.26 2.93,-7.07l0,0c0.45,-0.45 0.93,-0.84 1.44,-1.19C6.39,3.73 6.4,3.72 6.42,3.71c0.2,-0.14 0.41,-0.26 0.62,-0.38c0.08,-0.05 0.15,-0.09 0.23,-0.14c0.17,-0.09 0.33,-0.16 0.5,-0.24c0.13,-0.06 0.27,-0.13 0.4,-0.19C8.3,2.71 8.42,2.67 8.55,2.63c0.19,-0.07 0.38,-0.14 0.58,-0.2c0.07,-0.02 0.14,-0.03 0.21,-0.05C10.18,2.14 11.07,2 12,2c0.65,0 1.29,0.07 1.91,0.19c0,0 0,0 0,0c0.25,0.05 0.5,0.11 0.75,0.18c0.07,0.02 0.14,0.03 0.22,0.06c0.19,0.06 0.38,0.13 0.57,0.2c0.12,0.05 0.25,0.09 0.37,0.14c0.14,0.06 0.27,0.12 0.4,0.18c0.17,0.08 0.34,0.16 0.51,0.25c0.08,0.04 0.15,0.09 0.23,0.14c0.21,0.12 0.42,0.24 0.62,0.38c0.01,0.01 0.03,0.02 0.04,0.03c0.51,0.35 0.99,0.74 1.45,1.19c0.24,0.24 0.47,0.49 0.68,0.75c0.04,0.04 0.06,0.09 0.1,0.13c0.17,0.22 0.34,0.45 0.5,0.68c0.01,0.01 0.02,0.03 0.03,0.04c0.69,1.05 1.17,2.21 1.42,3.44c0,0 0,0.01 0,0.01c0.06,0.29 0.1,0.58 0.13,0.87c0.01,0.04 0.01,0.09 0.02,0.13C21.98,11.32 22,11.66 22,12zM18.5,15c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S20.43,15 18.5,15z"/>
|
||||
</vector>
|
||||
25
packages/SystemUI/res/drawable/ic_stop_bubble.xml
Normal file
25
packages/SystemUI/res/drawable/ic_stop_bubble.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M21.98,18.32l-3.3,-3.3C20.47,15.11 21.89,16.53 21.98,18.32zM8.66,4.74C8.75,4.7 8.84,4.65 8.93,4.61c0.11,-0.05 0.23,-0.09 0.35,-0.13c0.14,-0.05 0.27,-0.1 0.41,-0.14C9.77,4.32 9.85,4.3 9.92,4.28c0.18,-0.05 0.36,-0.1 0.54,-0.13c0.03,-0.01 0.07,-0.01 0.1,-0.01c0.95,-0.17 1.93,-0.17 2.88,0c0.03,0.01 0.07,0.01 0.1,0.01c0.18,0.04 0.36,0.08 0.54,0.13c0.08,0.02 0.16,0.04 0.23,0.06c0.14,0.04 0.27,0.09 0.41,0.14c0.12,0.04 0.23,0.08 0.35,0.13c0.09,0.04 0.18,0.09 0.27,0.13c0.15,0.07 0.3,0.14 0.45,0.22c0.05,0.03 0.09,0.06 0.14,0.08c1.26,0.72 2.31,1.77 3.03,3.03c0.03,0.05 0.06,0.09 0.08,0.14c0.08,0.15 0.15,0.3 0.22,0.45c0.04,0.09 0.09,0.18 0.13,0.27c0.05,0.11 0.09,0.23 0.13,0.35c0.05,0.13 0.1,0.27 0.14,0.41c0.02,0.08 0.04,0.16 0.06,0.24c0.05,0.18 0.1,0.36 0.13,0.54c0.01,0.03 0.01,0.07 0.02,0.1c0.16,0.91 0.17,1.84 0.02,2.75l1.97,0.33C21.94,13.1 22,12.56 22,12c0,0 0,0 0,0s0,0 0,0c0,-0.34 -0.02,-0.68 -0.05,-1.01c0,-0.04 -0.01,-0.09 -0.02,-0.13c-0.03,-0.29 -0.07,-0.58 -0.13,-0.87c0,0 0,-0.01 0,-0.01c-0.25,-1.23 -0.73,-2.39 -1.42,-3.44c-0.01,-0.01 -0.02,-0.03 -0.03,-0.04c-0.15,-0.23 -0.32,-0.46 -0.5,-0.68c-0.03,-0.04 -0.06,-0.09 -0.1,-0.13c-0.21,-0.26 -0.44,-0.51 -0.68,-0.75c-0.45,-0.45 -0.94,-0.84 -1.45,-1.19c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03c-0.2,-0.14 -0.41,-0.26 -0.62,-0.38c-0.08,-0.04 -0.15,-0.09 -0.23,-0.14c-0.17,-0.09 -0.34,-0.17 -0.51,-0.25c-0.13,-0.06 -0.26,-0.13 -0.4,-0.18c-0.12,-0.05 -0.25,-0.09 -0.37,-0.14c-0.19,-0.07 -0.38,-0.14 -0.57,-0.2c-0.07,-0.02 -0.14,-0.04 -0.22,-0.06c-0.25,-0.07 -0.5,-0.13 -0.75,-0.18c0,0 0,0 0,0C13.29,2.07 12.65,2 12,2c-0.93,0 -1.82,0.14 -2.67,0.37C9.26,2.39 9.19,2.41 9.12,2.43c-0.2,0.06 -0.39,0.13 -0.58,0.2C8.42,2.67 8.3,2.71 8.18,2.76c-0.14,0.06 -0.27,0.12 -0.4,0.19C7.61,3.03 7.44,3.1 7.27,3.19C7.19,3.24 7.12,3.29 7.04,3.33C7.03,3.34 7.02,3.34 7.01,3.35l1.48,1.48C8.55,4.8 8.6,4.77 8.66,4.74zM2.71,1.29L1.29,2.71l2.97,2.97C2.85,7.4 2,9.6 2,12c0,2.76 1.12,5.26 2.93,7.07l0,0c0.45,0.45 0.94,0.85 1.45,1.2c0.01,0.01 0.02,0.02 0.04,0.03c0.21,0.14 0.42,0.27 0.64,0.39c0.07,0.04 0.14,0.09 0.21,0.13c0.17,0.09 0.35,0.17 0.53,0.25c0.13,0.06 0.25,0.12 0.38,0.18c0.13,0.05 0.26,0.1 0.39,0.14c0.18,0.07 0.36,0.14 0.55,0.19c0.08,0.02 0.16,0.04 0.23,0.06c0.24,0.07 0.48,0.13 0.73,0.18c0.01,0 0.01,0 0.02,0C10.72,21.93 11.35,22 12,22v-0.01c0.54,0 1.08,-0.05 1.62,-0.14l-0.35,-1.98c-1.13,0.18 -2.29,0.13 -3.4,-0.18c-0.06,-0.02 -0.11,-0.03 -0.17,-0.04c-0.16,-0.05 -0.31,-0.11 -0.46,-0.16c-0.1,-0.04 -0.2,-0.07 -0.29,-0.11c-0.11,-0.05 -0.22,-0.1 -0.32,-0.15c-0.13,-0.06 -0.27,-0.12 -0.4,-0.19c-0.06,-0.03 -0.13,-0.08 -0.19,-0.11c-0.17,-0.1 -0.33,-0.19 -0.49,-0.3c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03C5.39,17.16 4,14.74 4,12c0,-1.85 0.64,-3.54 1.7,-4.89l9.73,9.73C15.16,17.33 15,17.9 15,18.5c0,1.93 1.57,3.5 3.5,3.5c0.6,0 1.17,-0.16 1.66,-0.43l1.13,1.13l1.41,-1.41L2.71,1.29z"/>
|
||||
</vector>
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.systemui.bubbles;
|
||||
|
||||
import static android.app.Notification.FLAG_BUBBLE;
|
||||
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
|
||||
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
|
||||
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
|
||||
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
|
||||
@@ -30,7 +32,6 @@ import static android.view.View.VISIBLE;
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS;
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.systemui.statusbar.StatusBarState.SHADE;
|
||||
@@ -43,6 +44,9 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
@@ -83,6 +87,7 @@ import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
|
||||
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener;
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifCollection;
|
||||
@@ -169,6 +174,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
private final NotificationShadeWindowController mNotificationShadeWindowController;
|
||||
private final ZenModeController mZenModeController;
|
||||
private StatusBarStateListener mStatusBarStateListener;
|
||||
private INotificationManager mINotificationManager;
|
||||
|
||||
// Callback that updates BubbleOverflowActivity on data change.
|
||||
@Nullable private Runnable mOverflowCallback = null;
|
||||
@@ -293,11 +299,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
SysUiState sysUiState) {
|
||||
SysUiState sysUiState,
|
||||
INotificationManager notificationManager) {
|
||||
this(context, notificationShadeWindowController, statusBarStateController, shadeController,
|
||||
data, null /* synchronizer */, configurationController, interruptionStateProvider,
|
||||
zenModeController, notifUserManager, groupManager, entryManager,
|
||||
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState);
|
||||
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState,
|
||||
notificationManager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,7 +327,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
SysUiState sysUiState) {
|
||||
SysUiState sysUiState,
|
||||
INotificationManager notificationManager) {
|
||||
dumpManager.registerDumpable(TAG, this);
|
||||
mContext = context;
|
||||
mShadeController = shadeController;
|
||||
@@ -327,6 +336,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
mNotifUserManager = notifUserManager;
|
||||
mZenModeController = zenModeController;
|
||||
mFloatingContentCoordinator = floatingContentCoordinator;
|
||||
mINotificationManager = notificationManager;
|
||||
mZenModeController.addCallback(new ZenModeController.Callback() {
|
||||
@Override
|
||||
public void onZenChanged(int zen) {
|
||||
@@ -809,37 +819,43 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
* This method will collapse the shade, create the bubble without a flyout or dot, and suppress
|
||||
* the notification from appearing in the shade.
|
||||
*
|
||||
* @param entry the notification to show as a bubble.
|
||||
* @param entry the notification to change bubble state for.
|
||||
* @param shouldBubble whether the notification should show as a bubble or not.
|
||||
*/
|
||||
public void onUserCreatedBubbleFromNotification(NotificationEntry entry) {
|
||||
if (DEBUG_EXPERIMENTS || DEBUG_BUBBLE_CONTROLLER) {
|
||||
Log.d(TAG, "onUserCreatedBubble: " + entry.getKey());
|
||||
public void onUserChangedBubble(NotificationEntry entry, boolean shouldBubble) {
|
||||
NotificationChannel channel = entry.getChannel();
|
||||
final String appPkg = entry.getSbn().getPackageName();
|
||||
final int appUid = entry.getSbn().getUid();
|
||||
if (channel == null || appPkg == null) {
|
||||
return;
|
||||
}
|
||||
mShadeController.collapsePanel(true);
|
||||
entry.setFlagBubble(true);
|
||||
updateBubble(entry, true /* suppressFlyout */, false /* showInShade */);
|
||||
mUserCreatedBubbles.add(entry.getKey());
|
||||
mUserBlockedBubbles.remove(entry.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user has indicated that an active notification appearing as a bubble should
|
||||
* no longer be shown as a bubble.
|
||||
*
|
||||
* @param entry the notification to no longer show as a bubble.
|
||||
*/
|
||||
public void onUserDemotedBubbleFromNotification(NotificationEntry entry) {
|
||||
if (DEBUG_EXPERIMENTS || DEBUG_BUBBLE_CONTROLLER) {
|
||||
Log.d(TAG, "onUserDemotedBubble: " + entry.getKey());
|
||||
// Update the state in NotificationManagerService
|
||||
try {
|
||||
int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
|
||||
mBarService.onNotificationBubbleChanged(entry.getKey(), shouldBubble, flags);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
entry.setFlagBubble(false);
|
||||
removeBubble(entry, DISMISS_BLOCKED);
|
||||
mUserCreatedBubbles.remove(entry.getKey());
|
||||
if (BubbleExperimentConfig.isPackageWhitelistedToAutoBubble(
|
||||
mContext, entry.getSbn().getPackageName())) {
|
||||
// This package is whitelist but user demoted the bubble, let's save it so we don't
|
||||
// auto-bubble for the whitelist again.
|
||||
mUserBlockedBubbles.add(entry.getKey());
|
||||
|
||||
// Change the settings
|
||||
channel = NotificationChannelHelper.createConversationChannelIfNeeded(mContext,
|
||||
mINotificationManager, entry, channel);
|
||||
channel.setAllowBubbles(shouldBubble);
|
||||
try {
|
||||
int currentPref = mINotificationManager.getBubblePreferenceForPackage(appPkg, appUid);
|
||||
if (shouldBubble && currentPref == BUBBLE_PREFERENCE_NONE) {
|
||||
mINotificationManager.setBubblesAllowed(appPkg, appUid, BUBBLE_PREFERENCE_SELECTED);
|
||||
}
|
||||
mINotificationManager.updateNotificationChannelForPackage(appPkg, appUid, channel);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
|
||||
if (shouldBubble) {
|
||||
mShadeController.collapsePanel(true);
|
||||
if (entry.getRow() != null) {
|
||||
entry.getRow().updateBubbleButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -987,14 +1003,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
} else {
|
||||
// Update the flag for SysUI
|
||||
bubble.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
|
||||
if (bubble.getEntry().getRow() != null) {
|
||||
bubble.getEntry().getRow().updateBubbleButton();
|
||||
}
|
||||
|
||||
// Make sure NoMan knows it's not a bubble anymore so anyone querying it
|
||||
// will get right result back
|
||||
// Update the state in NotificationManagerService
|
||||
try {
|
||||
mBarService.onNotificationBubbleChanged(bubble.getKey(),
|
||||
false /* isBubble */);
|
||||
false /* isBubble */, 0 /* flags */);
|
||||
} catch (RemoteException e) {
|
||||
// Bad things have happened
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.bubbles.dagger;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.systemui.bubbles.BubbleController;
|
||||
@@ -64,14 +65,15 @@ public interface BubbleModule {
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
SysUiState sysUiState) {
|
||||
SysUiState sysUiState,
|
||||
INotificationManager notifManager) {
|
||||
return new BubbleController(
|
||||
context,
|
||||
notificationShadeWindowController,
|
||||
statusBarStateController,
|
||||
shadeController,
|
||||
data,
|
||||
/* synchronizer */null,
|
||||
null /* synchronizer */,
|
||||
configurationController,
|
||||
interruptionStateProvider,
|
||||
zenModeController,
|
||||
@@ -82,6 +84,7 @@ public interface BubbleModule {
|
||||
featureFlags,
|
||||
dumpManager,
|
||||
floatingContentCoordinator,
|
||||
sysUiState);
|
||||
sysUiState,
|
||||
notifManager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
|
||||
/**
|
||||
* Helps SystemUI create notification channels.
|
||||
*/
|
||||
public class NotificationChannelHelper {
|
||||
private static final String TAG = "NotificationChannelHelper";
|
||||
|
||||
/** Creates a conversation channel based on the shortcut info or notification title. */
|
||||
public static NotificationChannel createConversationChannelIfNeeded(
|
||||
Context context,
|
||||
INotificationManager notificationManager,
|
||||
NotificationEntry entry,
|
||||
NotificationChannel channel) {
|
||||
if (!TextUtils.isEmpty(channel.getConversationId())) {
|
||||
return channel;
|
||||
}
|
||||
final String conversationId = entry.getSbn().getShortcutId(context);
|
||||
final String pkg = entry.getSbn().getPackageName();
|
||||
final int appUid = entry.getSbn().getUid();
|
||||
if (TextUtils.isEmpty(conversationId) || TextUtils.isEmpty(pkg)) {
|
||||
return channel;
|
||||
}
|
||||
|
||||
String name;
|
||||
if (entry.getRanking().getShortcutInfo() != null) {
|
||||
name = entry.getRanking().getShortcutInfo().getShortLabel().toString();
|
||||
} else {
|
||||
Bundle extras = entry.getSbn().getNotification().extras;
|
||||
String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
|
||||
if (TextUtils.isEmpty(nameString)) {
|
||||
nameString = extras.getString(Notification.EXTRA_TITLE);
|
||||
}
|
||||
name = nameString;
|
||||
}
|
||||
|
||||
// If this channel is not already a customized conversation channel, create
|
||||
// a custom channel
|
||||
try {
|
||||
// TODO: When shortcuts are enforced remove this and use the shortcut label for naming
|
||||
channel.setName(context.getString(
|
||||
R.string.notification_summary_message_format,
|
||||
name, channel.getName()));
|
||||
notificationManager.createConversationNotificationChannelForPackage(
|
||||
pkg, appUid, entry.getSbn().getKey(), channel,
|
||||
conversationId);
|
||||
channel = notificationManager.getConversationNotificationChannel(
|
||||
context.getOpPackageName(), UserHandle.getUserId(appUid), pkg,
|
||||
channel.getId(), false, conversationId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Could not create conversation channel", e);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,7 @@ import com.android.internal.widget.CachingIconView;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.Interpolators;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.bubbles.BubbleController;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
@@ -579,6 +580,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
}
|
||||
|
||||
/** Call when bubble state has changed and the button on the notification should be updated. */
|
||||
public void updateBubbleButton() {
|
||||
for (NotificationContentView l : mLayouts) {
|
||||
l.updateBubbleButton(mEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateShelfIconColor() {
|
||||
StatusBarIconView expandedIcon = mEntry.getIcons().getShelfIcon();
|
||||
@@ -1086,6 +1094,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
updateClickAndFocus();
|
||||
}
|
||||
|
||||
/** The click listener for the bubble button. */
|
||||
public View.OnClickListener getBubbleClickListener() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Dependency.get(BubbleController.class)
|
||||
.onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */);
|
||||
mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateClickAndFocus() {
|
||||
boolean normalChild = !isChildInGroup() || isGroupExpanded();
|
||||
boolean clickable = mOnClickListener != null && normalChild;
|
||||
@@ -1267,7 +1287,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
return mNotificationColor;
|
||||
}
|
||||
|
||||
private void updateNotificationColor() {
|
||||
public void updateNotificationColor() {
|
||||
Configuration currentConfig = getResources().getConfiguration();
|
||||
boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
|
||||
== Configuration.UI_MODE_NIGHT_YES;
|
||||
@@ -1613,6 +1633,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
mFalsingManager = falsingManager;
|
||||
mStatusbarStateController = statusBarStateController;
|
||||
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
|
||||
for (NotificationContentView l : mLayouts) {
|
||||
l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
private void initDimens() {
|
||||
|
||||
@@ -16,13 +16,18 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.row;
|
||||
|
||||
|
||||
import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -47,6 +52,7 @@ import com.android.systemui.statusbar.SmartReplyController;
|
||||
import com.android.systemui.statusbar.TransformableView;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
|
||||
import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
|
||||
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
@@ -118,6 +124,7 @@ public class NotificationContentView extends FrameLayout {
|
||||
private NotificationGroupManager mGroupManager;
|
||||
private RemoteInputController mRemoteInputController;
|
||||
private Runnable mExpandedVisibleListener;
|
||||
private PeopleNotificationIdentifier mPeopleIdentifier;
|
||||
/**
|
||||
* List of listeners for when content views become inactive (i.e. not the showing view).
|
||||
*/
|
||||
@@ -454,6 +461,9 @@ public class NotificationContentView extends FrameLayout {
|
||||
mExpandedChild = child;
|
||||
mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
|
||||
mContainingNotification);
|
||||
if (mContainingNotification != null) {
|
||||
applyBubbleAction(mExpandedChild, mContainingNotification.getEntry());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,6 +503,9 @@ public class NotificationContentView extends FrameLayout {
|
||||
mHeadsUpChild = child;
|
||||
mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
|
||||
mContainingNotification);
|
||||
if (mContainingNotification != null) {
|
||||
applyBubbleAction(mHeadsUpChild, mContainingNotification.getEntry());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1138,6 +1151,8 @@ public class NotificationContentView extends FrameLayout {
|
||||
mForceSelectNextLayout = true;
|
||||
mPreviousExpandedRemoteInputIntent = null;
|
||||
mPreviousHeadsUpRemoteInputIntent = null;
|
||||
applyBubbleAction(mExpandedChild, entry);
|
||||
applyBubbleAction(mHeadsUpChild, entry);
|
||||
}
|
||||
|
||||
private void updateAllSingleLineViews() {
|
||||
@@ -1308,6 +1323,58 @@ public class NotificationContentView extends FrameLayout {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to update state of the bubble button (i.e. does it show bubble or unbubble or no
|
||||
* icon at all).
|
||||
*
|
||||
* @param entry the new entry to use.
|
||||
*/
|
||||
public void updateBubbleButton(NotificationEntry entry) {
|
||||
applyBubbleAction(mExpandedChild, entry);
|
||||
}
|
||||
|
||||
private boolean isBubblesEnabled() {
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
NOTIFICATION_BUBBLES, 0) == 1;
|
||||
}
|
||||
|
||||
private void applyBubbleAction(View layout, NotificationEntry entry) {
|
||||
if (layout == null || mContainingNotification == null || mPeopleIdentifier == null) {
|
||||
return;
|
||||
}
|
||||
ImageView bubbleButton = layout.findViewById(com.android.internal.R.id.bubble_button);
|
||||
View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
|
||||
if (bubbleButton == null || actionContainer == null) {
|
||||
return;
|
||||
}
|
||||
boolean isPerson =
|
||||
mPeopleIdentifier.getPeopleNotificationType(entry.getSbn(), entry.getRanking())
|
||||
!= PeopleNotificationIdentifier.TYPE_NON_PERSON;
|
||||
boolean showButton = isBubblesEnabled()
|
||||
&& isPerson
|
||||
&& entry.getBubbleMetadata() != null;
|
||||
if (showButton) {
|
||||
Drawable d = mContext.getResources().getDrawable(entry.isBubble()
|
||||
? R.drawable.ic_stop_bubble
|
||||
: R.drawable.ic_create_bubble);
|
||||
mContainingNotification.updateNotificationColor();
|
||||
final int tint = mContainingNotification.getNotificationColor();
|
||||
d.setTint(tint);
|
||||
|
||||
String contentDescription = mContext.getResources().getString(entry.isBubble()
|
||||
? R.string.notification_conversation_unbubble
|
||||
: R.string.notification_conversation_bubble);
|
||||
|
||||
bubbleButton.setContentDescription(contentDescription);
|
||||
bubbleButton.setImageDrawable(d);
|
||||
bubbleButton.setOnClickListener(mContainingNotification.getBubbleClickListener());
|
||||
bubbleButton.setVisibility(VISIBLE);
|
||||
actionContainer.setVisibility(VISIBLE);
|
||||
} else {
|
||||
bubbleButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void applySmartReplyView(
|
||||
SmartRepliesAndActions smartRepliesAndActions,
|
||||
NotificationEntry entry) {
|
||||
@@ -1512,6 +1579,10 @@ public class NotificationContentView extends FrameLayout {
|
||||
mContainingNotification = containingNotification;
|
||||
}
|
||||
|
||||
public void setPeopleNotificationIdentifier(PeopleNotificationIdentifier peopleIdentifier) {
|
||||
mPeopleIdentifier = peopleIdentifier;
|
||||
}
|
||||
|
||||
public void requestSelectLayout(boolean needsAnimation) {
|
||||
selectLayout(needsAnimation, false);
|
||||
}
|
||||
|
||||
@@ -40,11 +40,9 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
import android.transition.ChangeBounds;
|
||||
@@ -53,7 +51,6 @@ import android.transition.TransitionManager;
|
||||
import android.transition.TransitionSet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.ImageView;
|
||||
@@ -64,6 +61,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settingslib.notification.ConversationIconFactory;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
|
||||
import com.android.systemui.statusbar.notification.VisualStabilityManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
|
||||
@@ -205,7 +203,8 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
}
|
||||
mShortcutInfo = entry.getRanking().getShortcutInfo();
|
||||
|
||||
createConversationChannelIfNeeded();
|
||||
mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded(
|
||||
getContext(), mINotificationManager, entry, mNotificationChannel);
|
||||
|
||||
bindHeader();
|
||||
bindActions();
|
||||
@@ -214,27 +213,6 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
done.setOnClickListener(mOnDone);
|
||||
}
|
||||
|
||||
void createConversationChannelIfNeeded() {
|
||||
// If this channel is not already a customized conversation channel, create
|
||||
// a custom channel
|
||||
if (TextUtils.isEmpty(mNotificationChannel.getConversationId())) {
|
||||
try {
|
||||
// TODO: remove
|
||||
mNotificationChannel.setName(mContext.getString(
|
||||
R.string.notification_summary_message_format,
|
||||
getName(), mNotificationChannel.getName()));
|
||||
mINotificationManager.createConversationNotificationChannelForPackage(
|
||||
mPackageName, mAppUid, mSbn.getKey(), mNotificationChannel,
|
||||
mConversationId);
|
||||
mNotificationChannel = mINotificationManager.getConversationNotificationChannel(
|
||||
mContext.getOpPackageName(), UserHandle.getUserId(mAppUid), mPackageName,
|
||||
mNotificationChannel.getId(), false, mConversationId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Could not create conversation channel", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindActions() {
|
||||
|
||||
// TODO: b/152050825
|
||||
@@ -318,24 +296,6 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
private void bindName() {
|
||||
TextView name = findViewById(R.id.name);
|
||||
name.setText(getName());
|
||||
}
|
||||
|
||||
private String getName() {
|
||||
if (mShortcutInfo != null) {
|
||||
return mShortcutInfo.getShortLabel().toString();
|
||||
} else {
|
||||
Bundle extras = mSbn.getNotification().extras;
|
||||
String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE);
|
||||
if (TextUtils.isEmpty(nameString)) {
|
||||
nameString = extras.getString(Notification.EXTRA_TITLE);
|
||||
}
|
||||
return nameString;
|
||||
}
|
||||
}
|
||||
|
||||
private void bindPackage() {
|
||||
ApplicationInfo info;
|
||||
try {
|
||||
|
||||
@@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.IActivityManager;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.res.Resources;
|
||||
@@ -273,7 +274,8 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
mFeatureFlagsOldPipeline,
|
||||
mDumpManager,
|
||||
mFloatingContentCoordinator,
|
||||
mSysUiState);
|
||||
mSysUiState,
|
||||
mock(INotificationManager.class));
|
||||
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
|
||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.IActivityManager;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.res.Resources;
|
||||
@@ -250,7 +251,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
mFeatureFlagsNewPipeline,
|
||||
mDumpManager,
|
||||
mFloatingContentCoordinator,
|
||||
mSysUiState);
|
||||
mSysUiState,
|
||||
mock(INotificationManager.class));
|
||||
mBubbleController.addNotifCallback(mNotifCallback);
|
||||
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
|
||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.bubbles;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
@@ -54,12 +55,14 @@ public class TestableBubbleController extends BubbleController {
|
||||
FeatureFlags featureFlags,
|
||||
DumpManager dumpManager,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
SysUiState sysUiState) {
|
||||
SysUiState sysUiState,
|
||||
INotificationManager notificationManager) {
|
||||
super(context,
|
||||
notificationShadeWindowController, statusBarStateController, shadeController,
|
||||
data, Runnable::run, configurationController, interruptionStateProvider,
|
||||
zenModeController, lockscreenUserManager, groupManager, entryManager,
|
||||
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState);
|
||||
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState,
|
||||
notificationManager);
|
||||
setInflateSynchronously(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public interface NotificationDelegate {
|
||||
/**
|
||||
* Called when the state of {@link Notification#FLAG_BUBBLE} is changed.
|
||||
*/
|
||||
void onNotificationBubbleChanged(String key, boolean isBubble);
|
||||
void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
|
||||
/**
|
||||
* Called when the state of {@link Notification.BubbleMetadata#FLAG_SUPPRESS_NOTIFICATION}
|
||||
* changes.
|
||||
|
||||
@@ -1196,14 +1196,7 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationBubbleChanged(String key, boolean isBubble) {
|
||||
String pkg;
|
||||
synchronized (mNotificationLock) {
|
||||
NotificationRecord r = mNotificationsByKey.get(key);
|
||||
pkg = r != null && r.getSbn() != null ? r.getSbn().getPackageName() : null;
|
||||
}
|
||||
boolean isAppForeground = pkg != null
|
||||
&& mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
|
||||
public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) {
|
||||
synchronized (mNotificationLock) {
|
||||
NotificationRecord r = mNotificationsByKey.get(key);
|
||||
if (r != null) {
|
||||
@@ -1220,8 +1213,13 @@ public class NotificationManagerService extends SystemService {
|
||||
// be applied there.
|
||||
r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
|
||||
r.setFlagBubbleRemoved(false);
|
||||
if (r.getNotification().getBubbleMetadata() != null) {
|
||||
r.getNotification().getBubbleMetadata().setFlags(flags);
|
||||
}
|
||||
// Force isAppForeground true here, because for sysui's purposes we
|
||||
// want to adjust the flag behaviour.
|
||||
mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(),
|
||||
r, isAppForeground));
|
||||
r, true /* isAppForeground*/));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1380,11 +1380,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationBubbleChanged(String key, boolean isBubble) {
|
||||
public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) {
|
||||
enforceStatusBarService();
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mNotificationDelegate.onNotificationBubbleChanged(key, isBubble);
|
||||
mNotificationDelegate.onNotificationBubbleChanged(key, isBubble, flags);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
@@ -5548,7 +5548,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0);
|
||||
|
||||
// Notify we're not a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false);
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
|
||||
waitForIdle();
|
||||
|
||||
// Make sure we are not a bubble
|
||||
@@ -5587,7 +5587,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
reset(mListeners);
|
||||
|
||||
// Notify we are now a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true);
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
|
||||
waitForIdle();
|
||||
|
||||
// Make sure we are a bubble
|
||||
@@ -5618,7 +5618,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
|
||||
|
||||
// Notify we are now a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true);
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
|
||||
waitForIdle();
|
||||
|
||||
// We still wouldn't be a bubble because the notification didn't meet requirements
|
||||
@@ -5646,7 +5646,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertFalse(recordToCheck.isFlagBubbleRemoved());
|
||||
|
||||
// Notify we're not a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false);
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
|
||||
waitForIdle();
|
||||
// Flag should be modified
|
||||
recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
|
||||
@@ -5681,14 +5681,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertFalse(recordToCheck.isFlagBubbleRemoved());
|
||||
|
||||
// Notify we're not a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false);
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0);
|
||||
waitForIdle();
|
||||
// Flag should be modified
|
||||
recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
|
||||
assertTrue(recordToCheck.isFlagBubbleRemoved());
|
||||
|
||||
// Notify we are a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true);
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0);
|
||||
waitForIdle();
|
||||
// And the flag is reset
|
||||
assertFalse(recordToCheck.isFlagBubbleRemoved());
|
||||
|
||||
Reference in New Issue
Block a user