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

Commit e53b6c8b authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove/destroy status bar window view when display is removed" into main

parents a45a83a4 faa04afe
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.window

import android.platform.test.annotations.EnableFlags
import android.view.Display.DEFAULT_DISPLAY
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.testKosmos
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.never
import org.mockito.kotlin.verify

@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val fakeDisplayRepository = kosmos.displayRepository
    private val testScope = kosmos.testScope

    private val underTest by lazy { kosmos.multiDisplayStatusBarWindowControllerStore }

    @Before
    fun start() {
        underTest.start()
    }

    @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }

    @Test
    fun beforeDisplayRemoved_doesNotStopInstances() =
        testScope.runTest {
            val instance = underTest.forDisplay(DEFAULT_DISPLAY)

            verify(instance, never()).stop()
        }

    @Test
    fun displayRemoved_stopsInstance() =
        testScope.runTest {
            val instance = underTest.forDisplay(DEFAULT_DISPLAY)

            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)

            verify(instance).stop()
        }
}
+68 −0
Original line number Diff line number Diff line
@@ -17,12 +17,17 @@ package com.android.systemui.statusbar.window

import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.fakeWindowManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.fragments.fragmentService
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.policy.statusBarConfigurationController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
@@ -37,6 +42,9 @@ class StatusBarWindowControllerImplTest : SysuiTestCase() {
        testKosmos().also { it.statusBarWindowViewInflater = it.fakeStatusBarWindowViewInflater }

    private val underTest = kosmos.statusBarWindowControllerImpl
    private val fakeExecutor = kosmos.fakeExecutor
    private val fakeWindowManager = kosmos.fakeWindowManager
    private val mockFragmentService = kosmos.fragmentService
    private val fakeStatusBarWindowViewInflater = kosmos.fakeStatusBarWindowViewInflater
    private val statusBarConfigurationController = kosmos.statusBarConfigurationController

@@ -59,4 +67,64 @@ class StatusBarWindowControllerImplTest : SysuiTestCase() {

        verify(mockWindowView, never()).setStatusBarConfigurationController(any())
    }

    @Test
    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarConnectedDisplays.FLAG_NAME)
    fun stop_statusBarModernizationFlagEnabled_doesNotRemoveFragment() {
        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()

        underTest.stop()
        fakeExecutor.runAllReady()

        verify(mockFragmentService, never()).removeAndDestroy(windowView)
    }

    @Test
    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
    @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
    fun stop_statusBarModernizationFlagDisabled_removesFragment() {
        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()

        underTest.stop()
        fakeExecutor.runAllReady()

        verify(mockFragmentService).removeAndDestroy(windowView)
    }

    @Test
    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
    @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
    fun stop_statusBarModernizationFlagDisabled_removesFragmentOnExecutor() {
        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()

        underTest.stop()

        verify(mockFragmentService, never()).removeAndDestroy(windowView)
        fakeExecutor.runAllReady()
        verify(mockFragmentService).removeAndDestroy(windowView)
    }

    @Test
    @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
    fun stop_removesWindowViewFromWindowManager() {
        underTest.attach()
        underTest.stop()

        assertThat(fakeWindowManager.addedViews).isEmpty()
    }

    @Test(expected = IllegalStateException::class)
    @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
    fun stop_connectedDisplaysFlagDisabled_crashes() {
        underTest.stop()
    }

    @Test
    fun attach_windowViewAddedToWindowManager() {
        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()

        underTest.attach()

        assertThat(fakeWindowManager.addedViews.keys).containsExactly(windowView)
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -36,6 +36,9 @@ interface StatusBarWindowController {
    /** Adds the status bar view to the window manager. */
    fun attach()

    /** Called when work should stop and resources should be released. */
    fun stop()

    /** Adds the given view to the status bar window view. */
    fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams)

@@ -78,7 +81,7 @@ interface StatusBarWindowController {
     */
    fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean)

    interface Factory {
    fun interface Factory {
        fun create(
            context: Context,
            viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
+20 −1
Original line number Diff line number Diff line
@@ -51,10 +51,12 @@ import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.animation.DelegateTransitionAnimatorController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
import com.android.systemui.statusbar.core.StatusBarRootModernization;
import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.window.StatusBarWindowModule.InternalWindowViewInflater;
@@ -66,6 +68,7 @@ import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;

import java.util.Optional;
import java.util.concurrent.Executor;

/**
 * Encapsulates all logic for the status bar window state management.
@@ -79,6 +82,7 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController
    private final StatusBarConfigurationController mStatusBarConfigurationController;
    private final IWindowManager mIWindowManager;
    private final StatusBarContentInsetsProvider mContentInsetsProvider;
    private final Executor mMainExecutor;
    private int mBarHeight = -1;
    private final State mCurrentState = new State();
    private boolean mIsAttached;
@@ -101,12 +105,14 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController
            IWindowManager iWindowManager,
            @Assisted StatusBarContentInsetsProvider contentInsetsProvider,
            FragmentService fragmentService,
            Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider) {
            Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider,
            @Main Executor mainExecutor) {
        mContext = context;
        mWindowManager = viewCaptureAwareWindowManager;
        mStatusBarConfigurationController = statusBarConfigurationController;
        mIWindowManager = iWindowManager;
        mContentInsetsProvider = contentInsetsProvider;
        mMainExecutor = mainExecutor;
        mStatusBarWindowView = statusBarWindowViewInflater.inflate(context);
        mFragmentService = fragmentService;
        mLaunchAnimationContainer = mStatusBarWindowView.findViewById(
@@ -166,6 +172,19 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController
        apply(mCurrentState);
    }

    @Override
    public void stop() {
        StatusBarConnectedDisplays.assertInNewMode();

        mWindowManager.removeView(mStatusBarWindowView);

        if (StatusBarRootModernization.isEnabled()) {
            return;
        }
        // Fragment transactions need to happen on the main thread.
        mMainExecutor.execute(() -> mFragmentService.removeAndDestroy(mStatusBarWindowView));
    }

    @Override
    public void addViewToWindow(@NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) {
        mStatusBarWindowView.addView(view, layoutParams);
+4 −0
Original line number Diff line number Diff line
@@ -70,6 +70,10 @@ constructor(
        )
    }

    override suspend fun onDisplayRemovalAction(instance: StatusBarWindowController) {
        instance.stop()
    }

    override val instanceClass = StatusBarWindowController::class.java
}

Loading