Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc433aeb authored by Liran Binyamin's avatar Liran Binyamin Committed by Android (Google) Code Review
Browse files

Merge "Log bubble entry points" into main

parents 415f987f 3461cc34
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
+2 −0
Original line number Diff line number Diff line
@@ -28,4 +28,6 @@ enum class EntryPoint : Parcelable {
    HOTSEAT_ICON_MENU,
    TASKBAR_ICON_DRAG,
    ALL_APPS_ICON_DRAG,
    NOTIFICATION,
    NOTIFICATION_BUBBLE_BUTTON,
}
+16 −5
Original line number Diff line number Diff line
@@ -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);
    }

    /**
@@ -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);
    }

    /**
@@ -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()
@@ -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);
        }
    }
@@ -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);
        }
    }
+12 −0
Original line number Diff line number Diff line
@@ -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;

@@ -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
     *
+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
}