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

Commit abb3a22b authored by Mady Mellor's avatar Mady Mellor Committed by Android (Google) Code Review
Browse files

Merge changes from topic "remove-prod-props" into main

* changes:
  Remove canShowAsBubbleBar and instead use isShowingAsBubbleBar
  Remove BubbleProperties
  Rename methods specific to note-taking bubbles to reflect that
  Create BubbleControllerTest
  Separate the notion of "note bubble" and "app bubble"
parents cc373044 2e40d603
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.wm.shell.multivalenttests">

    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>

    <application android:debuggable="true" android:supportsRtl="true" >
        <uses-library android:name="android.test.runner" />
        <activity android:name="com.android.wm.shell.bubbles.bar.BubbleBarAnimationHelperTest$TestActivity"
            android:exported="true"/>

        <activity android:name=".bubbles.TestActivity"
            android:allowEmbedded="true"
            android:documentLaunchMode="always"
            android:excludeFromRecents="true"
            android:exported="false"
            android:resizeableActivity="true" />
    </application>

    <instrumentation
+1 −2
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import com.android.internal.statusbar.IStatusBarService
import com.android.wm.shell.Flags
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
import com.android.wm.shell.bubbles.properties.ProdBubbleProperties
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayImeController
@@ -288,7 +287,7 @@ class BubbleControllerBubbleBarTest {
            mock<Transitions>(),
            SyncTransactionQueue(TransactionPool(), mainExecutor),
            mock<IWindowManager>(),
            ProdBubbleProperties,
            BubbleResizabilityChecker()
        )
    }

+231 −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.
 */

package com.android.wm.shell.bubbles

import android.content.Context
import android.content.Intent
import android.content.pm.LauncherApps
import android.content.pm.PackageManager
import android.graphics.drawable.Icon
import android.os.Handler
import android.os.UserHandle
import android.os.UserManager
import android.view.IWindowManager
import android.view.WindowManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.protolog.ProtoLog
import com.android.internal.statusbar.IStatusBarService
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayImeController
import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.common.TaskStackListenerImpl
import com.android.wm.shell.common.TestShellExecutor
import com.android.wm.shell.common.TestSyncExecutor
import com.android.wm.shell.draganddrop.DragAndDropController
import com.android.wm.shell.recents.RecentTasksController
import com.android.wm.shell.shared.TransactionPool
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.taskview.TaskViewRepository
import com.android.wm.shell.taskview.TaskViewTransitions
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.unfold.UnfoldAnimationController
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.util.Optional

/** Tests for [BubbleControllerTest] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class BubbleControllerTest {

    private val context = ApplicationProvider.getApplicationContext<Context>()

    private lateinit var bubbleController: BubbleController
    private lateinit var bubblePositioner: BubblePositioner
    private lateinit var uiEventLoggerFake: UiEventLoggerFake
    private lateinit var bubbleLogger: BubbleLogger
    private lateinit var mainExecutor: TestShellExecutor
    private lateinit var bgExecutor: TestShellExecutor
    private lateinit var bubbleData: BubbleData
    private lateinit var eduController: BubbleEducationController

    @Before
    fun setUp() {
        ProtoLog.REQUIRE_PROTOLOGTOOL = false
        ProtoLog.init()

        uiEventLoggerFake = UiEventLoggerFake()
        bubbleLogger = BubbleLogger(uiEventLoggerFake)
        eduController = BubbleEducationController(context)

        mainExecutor = TestShellExecutor()
        bgExecutor = TestShellExecutor()

        // Tests don't have permission to add our window to windowManager, so we mock it :(
        val windowManager = mock<WindowManager>()
        val realWindowManager = context.getSystemService(WindowManager::class.java)
        // But we do want the metrics from the real one
        whenever(windowManager.currentWindowMetrics)
            .thenReturn(realWindowManager.currentWindowMetrics)

        bubblePositioner = BubblePositioner(context, windowManager)
        bubblePositioner.setShowingInBubbleBar(true)

        bubbleData = BubbleData(
            context, bubbleLogger, bubblePositioner, eduController,
            mainExecutor, bgExecutor
        )

        bubbleController =
            createBubbleController(
                bubbleData,
                windowManager,
                bubbleLogger,
                bubblePositioner,
                mainExecutor,
                bgExecutor,
            )
        bubbleController.asBubbles().setSysuiProxy(Mockito.mock(SysuiProxy::class.java))
        // Flush so that proxy gets set
        mainExecutor.flushAll()
    }

    @After
    fun tearDown() {
        getInstrumentation().waitForIdleSync()
    }

    @Test
    fun showOrHideNotesBubble_createsNoteBubble() {
        val intent = Intent(context, TestActivity::class.java)
        intent.setPackage(context.packageName)
        val user = UserHandle.of(0)
        val expectedKey = Bubble.getNoteBubbleKeyForApp(intent.getPackage(), user)

        getInstrumentation().runOnMainSync {
            bubbleController.showOrHideNotesBubble(intent, user, mock<Icon>())
        }
        getInstrumentation().waitForIdleSync()

        assertThat(bubbleController.hasBubbles()).isTrue()
        assertThat(bubbleData.getAnyBubbleWithKey(expectedKey)).isNotNull()
        assertThat(bubbleData.getAnyBubbleWithKey(expectedKey)!!.isNoteBubble).isTrue()
    }


    fun createBubbleController(
        bubbleData: BubbleData,
        windowManager: WindowManager?,
        bubbleLogger: BubbleLogger,
        bubblePositioner: BubblePositioner,
        mainExecutor: TestShellExecutor,
        bgExecutor: TestShellExecutor,
    ): BubbleController {
        val shellInit = ShellInit(mainExecutor)
        val shellCommandHandler = ShellCommandHandler()
        val shellController =
            ShellController(
                context,
                shellInit,
                shellCommandHandler,
                mock<DisplayInsetsController>(),
                mainExecutor,
            )
        val surfaceSynchronizer = { obj: Runnable -> obj.run() }

        val bubbleDataRepository =
            BubbleDataRepository(
                mock<LauncherApps>(),
                mainExecutor,
                bgExecutor,
                BubblePersistentRepository(context),
            )

        val shellTaskOrganizer = ShellTaskOrganizer(
            Mockito.mock<ShellInit>(ShellInit::class.java),
            ShellCommandHandler(),
            null,
            Optional.empty<UnfoldAnimationController>(),
            Optional.empty<RecentTasksController>(),
            TestSyncExecutor()
        )

        val resizeChecker: ResizabilityChecker =
            object : ResizabilityChecker {
                override fun isResizableActivity(
                    intent: Intent?,
                    packageManager: PackageManager, key: String
                ): Boolean {
                    return true
                }
            }

        val bubbleController = BubbleController(
            context,
            shellInit,
            shellCommandHandler,
            shellController,
            bubbleData,
            surfaceSynchronizer,
            FloatingContentCoordinator(),
            bubbleDataRepository,
            mock<IStatusBarService>(),
            windowManager,
            mock<DisplayInsetsController>(),
            mock<DisplayImeController>(),
            mock<UserManager>(),
            mock<LauncherApps>(),
            bubbleLogger,
            mock<TaskStackListenerImpl>(),
            shellTaskOrganizer,
            bubblePositioner,
            mock<DisplayController>(),
            Optional.empty(),
            mock<DragAndDropController>(),
            mainExecutor,
            mock<Handler>(),
            bgExecutor,
            mock<TaskViewRepository>(),
            mock<TaskViewTransitions>(),
            mock<Transitions>(),
            SyncTransactionQueue(TransactionPool(), mainExecutor),
            mock<IWindowManager>(),
            resizeChecker,
        )
        bubbleController.setInflateSynchronously(true)
        bubbleController.onInit()

        return bubbleController
    }
}
 No newline at end of file
+4 −4
Original line number Diff line number Diff line
@@ -154,19 +154,19 @@ class BubblePositionerTest {

    /** Test that the default resting position on tablet is middle right. */
    @Test
    fun testGetDefaultPosition_appBubble_onTablet() {
    fun testGetDefaultPosition_noteBubble_onTablet() {
        positioner.update(defaultDeviceConfig.copy(isLargeScreen = true))
        val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
        val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */)
        val startPosition = positioner.getDefaultStartPosition(true /* isNoteBubble */)
        assertThat(startPosition.x).isEqualTo(allowableStackRegion.right)
        assertThat(startPosition.y).isEqualTo(defaultYPosition)
    }

    @Test
    fun testGetRestingPosition_appBubble_onTablet_RTL() {
    fun testGetRestingPosition_noteBubble_onTablet_RTL() {
        positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true))
        val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
        val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */)
        val startPosition = positioner.getDefaultStartPosition(true /* isNoteBubble */)
        assertThat(startPosition.x).isEqualTo(allowableStackRegion.left)
        assertThat(startPosition.y).isEqualTo(defaultYPosition)
    }
+1 −2
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import com.android.internal.protolog.ProtoLog
import com.android.internal.statusbar.IStatusBarService
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.bubbles.properties.BubbleProperties
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayImeController
@@ -161,7 +160,7 @@ class BubbleViewInfoTaskTest {
                mock<Transitions>(),
                SyncTransactionQueue(TransactionPool(), mainExecutor),
                mock<IWindowManager>(),
                mock<BubbleProperties>()
                BubbleResizabilityChecker()
            )

        // TODO: (b/371829099) - when optional overflow is no longer flagged we can enable this
Loading