Loading libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt +95 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.bubbles import android.app.ActivityManager import android.app.Notification import android.app.TaskInfo import android.content.ComponentName import android.content.Context Loading @@ -34,6 +35,8 @@ import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.platform.test.flag.junit.SetFlagsRule import android.service.notification.NotificationListenerService import android.service.notification.StatusBarNotification import android.view.IWindowManager import android.view.InsetsSource import android.view.InsetsState Loading Loading @@ -62,6 +65,9 @@ import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.bubbles.Bubbles.BubbleExpandListener import com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_GESTURE import com.android.wm.shell.bubbles.Bubbles.SysuiProxy import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU import com.android.wm.shell.bubbles.logging.BubbleSessionTracker import com.android.wm.shell.bubbles.logging.BubbleSessionTrackerImpl import com.android.wm.shell.bubbles.storage.BubblePersistentRepository Loading @@ -80,6 +86,7 @@ import com.android.wm.shell.draganddrop.DragAndDropController import com.android.wm.shell.shared.TransactionPool import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper import com.android.wm.shell.shared.bubbles.DeviceConfig import com.android.wm.shell.shared.bubbles.logging.EntryPoint import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController Loading Loading @@ -907,6 +914,94 @@ class BubbleControllerTest(flags: FlagsParameterization) { .that(overflowBubble.isInflated).isFalse() } @Test fun bubbleCreatedFromNotification_shouldLogEntryPoint() { bubbleController.asBubbles().onEntryAdded(createBubbleEntry(pkgName = "package.name")) mainExecutor.flushAll() assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) val log = uiEventLoggerFake.logs.first() assertThat(log.packageName).isEqualTo("package.name") assertThat(log.eventId).isEqualTo(BUBBLE_CREATED_FROM_NOTIF.id) } @Test fun bubbleCreatedFromNotificationButton_shouldLogEntryPoint() { bubbleController.asBubbles().onEntryUpdated( createBubbleEntry(pkgName = "package.name"), /* shouldBubbleUp= */ true, /* fromSystem= */ true ) mainExecutor.flushAll() assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) val log = uiEventLoggerFake.logs.first() assertThat(log.packageName).isEqualTo("package.name") assertThat(log.eventId).isEqualTo(BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON.id) } @Test fun bubbleNotificationUpdated_shouldNotLogEntryPoint() { val bubble = createBubble("bubble-key") getInstrumentation().runOnMainSync { bubbleController.inflateAndAdd( bubble, /* suppressFlyout= */ true, /* showInShade= */ true ) } bubbleController.asBubbles().onEntryUpdated( createBubbleEntry(bubbleKey = "bubble-key", pkgName = "package.name"), /* shouldBubbleUp= */ true, /* fromSystem= */ true ) mainExecutor.flushAll() assertThat(uiEventLoggerFake.logs).isEmpty() } @EnableFlags(FLAG_ENABLE_CREATE_ANY_BUBBLE) @Test fun expandStackAndSelectBubble_shouldLogEntryPoint() { val intent = Intent().apply { setPackage("package.name") } getInstrumentation().runOnMainSync { bubbleController.expandStackAndSelectBubble( intent, UserHandle.of(0), EntryPoint.ALL_APPS_ICON_MENU, /* bubbleBarLocation= */ null ) } assertThat(uiEventLoggerFake.logs).isNotEmpty() val log = uiEventLoggerFake.logs.first() assertThat(log.packageName).isEqualTo("package.name") assertThat(log.eventId).isEqualTo(BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU.id) } private fun createBubbleEntry(bubbleKey: String = "key", pkgName: String): BubbleEntry { val notif = Notification.Builder(context) .setBubbleMetadata(Notification.BubbleMetadata.Builder("shortcutId").build()) .setFlag(Notification.FLAG_BUBBLE, true) .build() val sbn = mock<StatusBarNotification>().stub { on { key } doReturn bubbleKey on { packageName } doReturn pkgName on { notification } doReturn notif } return BubbleEntry( sbn, mock<NotificationListenerService.Ranking>(), /* isDismissable= */ false, /* shouldSuppressNotificationDot= */ true, /* shouldSuppressNotificationList= */ true, /* shouldSuppressPeek= */ true ) } private fun createBubble(key: String, taskId: Int = 0): Bubble { val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) val shortcutInfo = ShortcutInfo.Builder(context, "fakeId").setIcon(icon).build() Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/logging/EntryPoint.kt +2 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,6 @@ enum class EntryPoint : Parcelable { HOTSEAT_ICON_MENU, TASKBAR_ICON_DRAG, ALL_APPS_ICON_DRAG, NOTIFICATION, NOTIFICATION_BUBBLE_BUTTON, } libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +16 −5 Original line number Diff line number Diff line Loading @@ -1741,7 +1741,7 @@ public class BubbleController implements ConfigurationChangeListener, bubbleBarLocation == null ? null : new UpdateLocationRequest(bubbleBarLocation, UpdateSource.APP_ICON_DRAG); expandStackAndSelectAppBubble(b, updateLocationRequest); expandStackAndSelectAppBubble(b, entryPoint, updateLocationRequest); } /** Loading @@ -1762,7 +1762,7 @@ public class BubbleController implements ConfigurationChangeListener, bubbleBarLocation == null ? null : new UpdateLocationRequest(bubbleBarLocation, UpdateSource.APP_ICON_DRAG); expandStackAndSelectAppBubble(b, updateLocationRequest); expandStackAndSelectAppBubble(b, entryPoint, updateLocationRequest); } /** Loading @@ -1781,16 +1781,20 @@ public class BubbleController implements ConfigurationChangeListener, bubbleBarLocation == null ? null : new UpdateLocationRequest(bubbleBarLocation, UpdateSource.APP_ICON_DRAG); expandStackAndSelectAppBubble(b, updateLocationRequest); expandStackAndSelectAppBubble(b, entryPoint, updateLocationRequest); } void expandStackAndSelectAppBubble(Bubble b) { expandStackAndSelectAppBubble(b, /* updateLocationRequest= */ null); expandStackAndSelectAppBubble(b, /* entryPoint= */ null, /* updateLocationRequest= */ null); } void expandStackAndSelectAppBubble(Bubble b, private void expandStackAndSelectAppBubble(Bubble b, @Nullable EntryPoint entryPoint, @Nullable UpdateLocationRequest updateLocationRequest) { if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return; if (entryPoint != null) { mLogger.logEntryPoint(isShowingAsBubbleBar(), entryPoint, b.getPackageName()); } BubbleBarLocation location = isShowingAsBubbleBar() && updateLocationRequest != null ? updateLocationRequest.getLocation() Loading Loading @@ -2393,6 +2397,8 @@ public class BubbleController implements ConfigurationChangeListener, private void onEntryAdded(BubbleEntry entry) { if (canLaunchInTaskView(mContext, entry)) { mLogger.logEntryPoint(isShowingAsBubbleBar(), EntryPoint.NOTIFICATION, entry.getStatusBarNotification().getPackageName()); updateBubble(entry); } } Loading @@ -2408,6 +2414,11 @@ public class BubbleController implements ConfigurationChangeListener, // It was previously a bubble but no longer a bubble -- lets remove it removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE); } else if (shouldBubble && entry.isBubble()) { if (!mBubbleData.hasAnyBubbleWithKey(entry.getKey())) { // only log the entry point if this is a newly promoted bubble mLogger.logEntryPoint(isShowingAsBubbleBar(), EntryPoint.NOTIFICATION_BUBBLE_BUTTON, entry.getStatusBarNotification().getPackageName()); } updateBubble(entry); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java +12 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.FrameworkStatsLog; import com.android.wm.shell.bubbles.logging.BubbleLoggerExt; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.shared.bubbles.logging.EntryPoint; import javax.inject.Inject; Loading Loading @@ -268,6 +270,16 @@ public class BubbleLogger { mUiEventLogger.logWithInstanceId(e, /* uid= */ 0, packageName, sessionId); } /** Logs a UiEvent for the bubble entry point. */ public void logEntryPoint(boolean isBubbleBar, EntryPoint entryPoint, String packageName) { UiEventLogger.UiEventEnum e = isBubbleBar ? BubbleLoggerExt.toBubbleBarUiEvent(entryPoint) : BubbleLoggerExt.toFloatingBubblesUiEvent(entryPoint); if (e != null) { mUiEventLogger.log(e, /* uid= */ 0, packageName); } } /** * Log when a bubble is removed from overflow in stack view * Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/logging/BubbleLoggerExt.kt 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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. */ @file:JvmName("BubbleLoggerExt") package com.android.wm.shell.bubbles.logging import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_DRAG import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_HOTSEAT_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_LAUNCHER_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_NOTIF import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_NOTIF_BUBBLE_BUTTON import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_DRAG import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_HOTSEAT_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_LAUNCHER_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON import com.android.wm.shell.shared.bubbles.logging.EntryPoint import com.android.wm.shell.shared.bubbles.logging.EntryPoint.ALL_APPS_ICON_DRAG import com.android.wm.shell.shared.bubbles.logging.EntryPoint.ALL_APPS_ICON_MENU import com.android.wm.shell.shared.bubbles.logging.EntryPoint.HOTSEAT_ICON_MENU import com.android.wm.shell.shared.bubbles.logging.EntryPoint.LAUNCHER_ICON_MENU import com.android.wm.shell.shared.bubbles.logging.EntryPoint.NOTIFICATION import com.android.wm.shell.shared.bubbles.logging.EntryPoint.NOTIFICATION_BUBBLE_BUTTON import com.android.wm.shell.shared.bubbles.logging.EntryPoint.TASKBAR_ICON_DRAG import com.android.wm.shell.shared.bubbles.logging.EntryPoint.TASKBAR_ICON_MENU /** Converts the [EntryPoint] to a bubble bar UiEvent. */ fun EntryPoint.toBubbleBarUiEvent() = when (this) { TASKBAR_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_MENU LAUNCHER_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_LAUNCHER_ICON_MENU ALL_APPS_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_MENU HOTSEAT_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_HOTSEAT_ICON_MENU TASKBAR_ICON_DRAG -> BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_DRAG ALL_APPS_ICON_DRAG -> BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_DRAG NOTIFICATION -> BUBBLE_BAR_CREATED_FROM_NOTIF NOTIFICATION_BUBBLE_BUTTON -> BUBBLE_BAR_CREATED_FROM_NOTIF_BUBBLE_BUTTON } /** Converts the [EntryPoint] to a floating bubbles UiEvent. */ fun EntryPoint.toFloatingBubblesUiEvent() = when (this) { LAUNCHER_ICON_MENU -> BUBBLE_CREATED_FROM_LAUNCHER_ICON_MENU ALL_APPS_ICON_MENU -> BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU HOTSEAT_ICON_MENU -> BUBBLE_CREATED_FROM_HOTSEAT_ICON_MENU NOTIFICATION -> BUBBLE_CREATED_FROM_NOTIF NOTIFICATION_BUBBLE_BUTTON -> BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON // the events below are only applicable to bubble bar ALL_APPS_ICON_DRAG, TASKBAR_ICON_DRAG, TASKBAR_ICON_MENU -> null } Loading
libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt +95 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.bubbles import android.app.ActivityManager import android.app.Notification import android.app.TaskInfo import android.content.ComponentName import android.content.Context Loading @@ -34,6 +35,8 @@ import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.platform.test.flag.junit.SetFlagsRule import android.service.notification.NotificationListenerService import android.service.notification.StatusBarNotification import android.view.IWindowManager import android.view.InsetsSource import android.view.InsetsState Loading Loading @@ -62,6 +65,9 @@ import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.bubbles.Bubbles.BubbleExpandListener import com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_GESTURE import com.android.wm.shell.bubbles.Bubbles.SysuiProxy import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU import com.android.wm.shell.bubbles.logging.BubbleSessionTracker import com.android.wm.shell.bubbles.logging.BubbleSessionTrackerImpl import com.android.wm.shell.bubbles.storage.BubblePersistentRepository Loading @@ -80,6 +86,7 @@ import com.android.wm.shell.draganddrop.DragAndDropController import com.android.wm.shell.shared.TransactionPool import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper import com.android.wm.shell.shared.bubbles.DeviceConfig import com.android.wm.shell.shared.bubbles.logging.EntryPoint import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController Loading Loading @@ -907,6 +914,94 @@ class BubbleControllerTest(flags: FlagsParameterization) { .that(overflowBubble.isInflated).isFalse() } @Test fun bubbleCreatedFromNotification_shouldLogEntryPoint() { bubbleController.asBubbles().onEntryAdded(createBubbleEntry(pkgName = "package.name")) mainExecutor.flushAll() assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) val log = uiEventLoggerFake.logs.first() assertThat(log.packageName).isEqualTo("package.name") assertThat(log.eventId).isEqualTo(BUBBLE_CREATED_FROM_NOTIF.id) } @Test fun bubbleCreatedFromNotificationButton_shouldLogEntryPoint() { bubbleController.asBubbles().onEntryUpdated( createBubbleEntry(pkgName = "package.name"), /* shouldBubbleUp= */ true, /* fromSystem= */ true ) mainExecutor.flushAll() assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) val log = uiEventLoggerFake.logs.first() assertThat(log.packageName).isEqualTo("package.name") assertThat(log.eventId).isEqualTo(BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON.id) } @Test fun bubbleNotificationUpdated_shouldNotLogEntryPoint() { val bubble = createBubble("bubble-key") getInstrumentation().runOnMainSync { bubbleController.inflateAndAdd( bubble, /* suppressFlyout= */ true, /* showInShade= */ true ) } bubbleController.asBubbles().onEntryUpdated( createBubbleEntry(bubbleKey = "bubble-key", pkgName = "package.name"), /* shouldBubbleUp= */ true, /* fromSystem= */ true ) mainExecutor.flushAll() assertThat(uiEventLoggerFake.logs).isEmpty() } @EnableFlags(FLAG_ENABLE_CREATE_ANY_BUBBLE) @Test fun expandStackAndSelectBubble_shouldLogEntryPoint() { val intent = Intent().apply { setPackage("package.name") } getInstrumentation().runOnMainSync { bubbleController.expandStackAndSelectBubble( intent, UserHandle.of(0), EntryPoint.ALL_APPS_ICON_MENU, /* bubbleBarLocation= */ null ) } assertThat(uiEventLoggerFake.logs).isNotEmpty() val log = uiEventLoggerFake.logs.first() assertThat(log.packageName).isEqualTo("package.name") assertThat(log.eventId).isEqualTo(BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU.id) } private fun createBubbleEntry(bubbleKey: String = "key", pkgName: String): BubbleEntry { val notif = Notification.Builder(context) .setBubbleMetadata(Notification.BubbleMetadata.Builder("shortcutId").build()) .setFlag(Notification.FLAG_BUBBLE, true) .build() val sbn = mock<StatusBarNotification>().stub { on { key } doReturn bubbleKey on { packageName } doReturn pkgName on { notification } doReturn notif } return BubbleEntry( sbn, mock<NotificationListenerService.Ranking>(), /* isDismissable= */ false, /* shouldSuppressNotificationDot= */ true, /* shouldSuppressNotificationList= */ true, /* shouldSuppressPeek= */ true ) } private fun createBubble(key: String, taskId: Int = 0): Bubble { val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) val shortcutInfo = ShortcutInfo.Builder(context, "fakeId").setIcon(icon).build() Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/logging/EntryPoint.kt +2 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,6 @@ enum class EntryPoint : Parcelable { HOTSEAT_ICON_MENU, TASKBAR_ICON_DRAG, ALL_APPS_ICON_DRAG, NOTIFICATION, NOTIFICATION_BUBBLE_BUTTON, }
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +16 −5 Original line number Diff line number Diff line Loading @@ -1741,7 +1741,7 @@ public class BubbleController implements ConfigurationChangeListener, bubbleBarLocation == null ? null : new UpdateLocationRequest(bubbleBarLocation, UpdateSource.APP_ICON_DRAG); expandStackAndSelectAppBubble(b, updateLocationRequest); expandStackAndSelectAppBubble(b, entryPoint, updateLocationRequest); } /** Loading @@ -1762,7 +1762,7 @@ public class BubbleController implements ConfigurationChangeListener, bubbleBarLocation == null ? null : new UpdateLocationRequest(bubbleBarLocation, UpdateSource.APP_ICON_DRAG); expandStackAndSelectAppBubble(b, updateLocationRequest); expandStackAndSelectAppBubble(b, entryPoint, updateLocationRequest); } /** Loading @@ -1781,16 +1781,20 @@ public class BubbleController implements ConfigurationChangeListener, bubbleBarLocation == null ? null : new UpdateLocationRequest(bubbleBarLocation, UpdateSource.APP_ICON_DRAG); expandStackAndSelectAppBubble(b, updateLocationRequest); expandStackAndSelectAppBubble(b, entryPoint, updateLocationRequest); } void expandStackAndSelectAppBubble(Bubble b) { expandStackAndSelectAppBubble(b, /* updateLocationRequest= */ null); expandStackAndSelectAppBubble(b, /* entryPoint= */ null, /* updateLocationRequest= */ null); } void expandStackAndSelectAppBubble(Bubble b, private void expandStackAndSelectAppBubble(Bubble b, @Nullable EntryPoint entryPoint, @Nullable UpdateLocationRequest updateLocationRequest) { if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return; if (entryPoint != null) { mLogger.logEntryPoint(isShowingAsBubbleBar(), entryPoint, b.getPackageName()); } BubbleBarLocation location = isShowingAsBubbleBar() && updateLocationRequest != null ? updateLocationRequest.getLocation() Loading Loading @@ -2393,6 +2397,8 @@ public class BubbleController implements ConfigurationChangeListener, private void onEntryAdded(BubbleEntry entry) { if (canLaunchInTaskView(mContext, entry)) { mLogger.logEntryPoint(isShowingAsBubbleBar(), EntryPoint.NOTIFICATION, entry.getStatusBarNotification().getPackageName()); updateBubble(entry); } } Loading @@ -2408,6 +2414,11 @@ public class BubbleController implements ConfigurationChangeListener, // It was previously a bubble but no longer a bubble -- lets remove it removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE); } else if (shouldBubble && entry.isBubble()) { if (!mBubbleData.hasAnyBubbleWithKey(entry.getKey())) { // only log the entry point if this is a newly promoted bubble mLogger.logEntryPoint(isShowingAsBubbleBar(), EntryPoint.NOTIFICATION_BUBBLE_BUTTON, entry.getStatusBarNotification().getPackageName()); } updateBubble(entry); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java +12 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.FrameworkStatsLog; import com.android.wm.shell.bubbles.logging.BubbleLoggerExt; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.shared.bubbles.logging.EntryPoint; import javax.inject.Inject; Loading Loading @@ -268,6 +270,16 @@ public class BubbleLogger { mUiEventLogger.logWithInstanceId(e, /* uid= */ 0, packageName, sessionId); } /** Logs a UiEvent for the bubble entry point. */ public void logEntryPoint(boolean isBubbleBar, EntryPoint entryPoint, String packageName) { UiEventLogger.UiEventEnum e = isBubbleBar ? BubbleLoggerExt.toBubbleBarUiEvent(entryPoint) : BubbleLoggerExt.toFloatingBubblesUiEvent(entryPoint); if (e != null) { mUiEventLogger.log(e, /* uid= */ 0, packageName); } } /** * Log when a bubble is removed from overflow in stack view * Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/logging/BubbleLoggerExt.kt 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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. */ @file:JvmName("BubbleLoggerExt") package com.android.wm.shell.bubbles.logging import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_DRAG import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_HOTSEAT_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_LAUNCHER_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_NOTIF import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_NOTIF_BUBBLE_BUTTON import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_DRAG import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_HOTSEAT_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_LAUNCHER_ICON_MENU import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF import com.android.wm.shell.bubbles.BubbleLogger.Event.BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON import com.android.wm.shell.shared.bubbles.logging.EntryPoint import com.android.wm.shell.shared.bubbles.logging.EntryPoint.ALL_APPS_ICON_DRAG import com.android.wm.shell.shared.bubbles.logging.EntryPoint.ALL_APPS_ICON_MENU import com.android.wm.shell.shared.bubbles.logging.EntryPoint.HOTSEAT_ICON_MENU import com.android.wm.shell.shared.bubbles.logging.EntryPoint.LAUNCHER_ICON_MENU import com.android.wm.shell.shared.bubbles.logging.EntryPoint.NOTIFICATION import com.android.wm.shell.shared.bubbles.logging.EntryPoint.NOTIFICATION_BUBBLE_BUTTON import com.android.wm.shell.shared.bubbles.logging.EntryPoint.TASKBAR_ICON_DRAG import com.android.wm.shell.shared.bubbles.logging.EntryPoint.TASKBAR_ICON_MENU /** Converts the [EntryPoint] to a bubble bar UiEvent. */ fun EntryPoint.toBubbleBarUiEvent() = when (this) { TASKBAR_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_MENU LAUNCHER_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_LAUNCHER_ICON_MENU ALL_APPS_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_MENU HOTSEAT_ICON_MENU -> BUBBLE_BAR_CREATED_FROM_HOTSEAT_ICON_MENU TASKBAR_ICON_DRAG -> BUBBLE_BAR_CREATED_FROM_TASKBAR_ICON_DRAG ALL_APPS_ICON_DRAG -> BUBBLE_BAR_CREATED_FROM_ALL_APPS_ICON_DRAG NOTIFICATION -> BUBBLE_BAR_CREATED_FROM_NOTIF NOTIFICATION_BUBBLE_BUTTON -> BUBBLE_BAR_CREATED_FROM_NOTIF_BUBBLE_BUTTON } /** Converts the [EntryPoint] to a floating bubbles UiEvent. */ fun EntryPoint.toFloatingBubblesUiEvent() = when (this) { LAUNCHER_ICON_MENU -> BUBBLE_CREATED_FROM_LAUNCHER_ICON_MENU ALL_APPS_ICON_MENU -> BUBBLE_CREATED_FROM_ALL_APPS_ICON_MENU HOTSEAT_ICON_MENU -> BUBBLE_CREATED_FROM_HOTSEAT_ICON_MENU NOTIFICATION -> BUBBLE_CREATED_FROM_NOTIF NOTIFICATION_BUBBLE_BUTTON -> BUBBLE_CREATED_FROM_NOTIF_BUBBLE_BUTTON // the events below are only applicable to bubble bar ALL_APPS_ICON_DRAG, TASKBAR_ICON_DRAG, TASKBAR_ICON_MENU -> null }