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

Commit 695b6123 authored by Chris Göllner's avatar Chris Göllner
Browse files

Status Bar - Extract interfaces of initialization related classes

This will allow to have different implementations of these interfaces.
It will be needed for multi display support, where we will have
multi display specific implementations.

Test: Build and run SystemUI
Flag: EXEMPT no changes. Just extracting classes into interfaces.
Bug: 367592591
Change-Id: Iec0984d423b60b851f34f1da9441a2eea7fb3fc3
parent c99762b2
Loading
Loading
Loading
Loading
+55 −40
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@
package com.android.systemui.statusbar.core

import android.app.Fragment
import com.android.systemui.res.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.fragments.FragmentHostManager
import com.android.systemui.res.R
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewUpdatedListener
import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions
import com.android.systemui.statusbar.phone.PhoneStatusBarView
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
@@ -33,31 +35,62 @@ import javax.inject.Provider
 * Responsible for creating the status bar window and initializing the root components of that
 * window (see [CollapsedStatusBarFragment])
 */
@SysUISingleton
class StatusBarInitializer @Inject constructor(
    private val windowController: StatusBarWindowController,
    private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
    private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>,
) {
interface StatusBarInitializer {

    var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener? = null
    var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener?

    /**
     * Creates the status bar window and root views, and initializes the component.
     *
     * TODO(b/277764509): Initialize the status bar via [CoreStartable#start].
     */
    fun initializeStatusBar() {
        windowController.fragmentHostManager.addTagListener(
    fun initializeStatusBar()

    interface OnStatusBarViewInitializedListener {

        /**
         * The status bar view has been initialized.
         *
         * @param component Dagger component that is created when the status bar view is created.
         *   Can be used to retrieve dependencies from that scope, including the status bar root
         *   view.
         */
        fun onStatusBarViewInitialized(component: StatusBarFragmentComponent)
    }

    interface OnStatusBarViewUpdatedListener {
        fun onStatusBarViewUpdated(
            statusBarView: PhoneStatusBarView,
            statusBarViewController: PhoneStatusBarViewController,
            statusBarTransitions: PhoneStatusBarTransitions,
        )
    }
}

@SysUISingleton
class StatusBarInitializerImpl
@Inject
constructor(
    private val windowController: StatusBarWindowController,
    private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
    private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>,
) : StatusBarInitializer {

    override var statusBarViewUpdatedListener: OnStatusBarViewUpdatedListener? = null

    override fun initializeStatusBar() {
        windowController.fragmentHostManager
            .addTagListener(
                CollapsedStatusBarFragment.TAG,
                object : FragmentHostManager.FragmentListener {
                    override fun onFragmentViewCreated(tag: String, fragment: Fragment) {
                        val statusBarFragmentComponent = (fragment as CollapsedStatusBarFragment)
                                .statusBarFragmentComponent ?: throw IllegalStateException()
                        val statusBarFragmentComponent =
                            (fragment as CollapsedStatusBarFragment).statusBarFragmentComponent
                                ?: throw IllegalStateException()
                        statusBarViewUpdatedListener?.onStatusBarViewUpdated(
                            statusBarFragmentComponent.phoneStatusBarView,
                            statusBarFragmentComponent.phoneStatusBarViewController,
                            statusBarFragmentComponent.phoneStatusBarTransitions
                            statusBarFragmentComponent.phoneStatusBarTransitions,
                        )
                        creationListeners.forEach { listener ->
                            listener.onStatusBarViewInitialized(statusBarFragmentComponent)
@@ -67,33 +100,15 @@ class StatusBarInitializer @Inject constructor(
                    override fun onFragmentViewDestroyed(tag: String?, fragment: Fragment?) {
                        // nop
                    }
                }
        ).fragmentManager
                },
            )
            .fragmentManager
            .beginTransaction()
            .replace(
                R.id.status_bar_container,
                collapsedStatusBarFragmentProvider.get(),
                    CollapsedStatusBarFragment.TAG
                CollapsedStatusBarFragment.TAG,
            )
            .commit()
    }

    interface OnStatusBarViewInitializedListener {

        /**
         * The status bar view has been initialized.
         *
         * @param component Dagger component that is created when the status bar view is created.
         * Can be used to retrieve dependencies from that scope, including the status bar root view.
         */
        fun onStatusBarViewInitialized(component: StatusBarFragmentComponent)
    }

    interface OnStatusBarViewUpdatedListener {
        fun onStatusBarViewUpdated(
            statusBarView: PhoneStatusBarView,
            statusBarViewController: PhoneStatusBarViewController,
            statusBarTransitions: PhoneStatusBarTransitions
        )
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -20,12 +20,16 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.statusbar.core.StatusBarInitializer
import com.android.systemui.statusbar.core.StatusBarInitializerImpl
import com.android.systemui.statusbar.data.StatusBarDataLayerModule
import com.android.systemui.statusbar.phone.LightBarController
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.statusbar.window.StatusBarWindowControllerImpl
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -57,6 +61,13 @@ abstract class StatusBarModule {
    @ClassKey(StatusBarSignalPolicy::class)
    abstract fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable

    @Binds abstract fun statusBarInitializer(impl: StatusBarInitializerImpl): StatusBarInitializer

    @Binds
    abstract fun statusBarWindowController(
        impl: StatusBarWindowControllerImpl
    ): StatusBarWindowController

    companion object {
        @Provides
        @SysUISingleton
+76 −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.view.View
import android.view.ViewGroup
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.fragments.FragmentHostManager
import java.util.Optional

/** Encapsulates all logic for the status bar window state management. */
interface StatusBarWindowController {
    val statusBarHeight: Int

    /** Rereads the status bar height and reapplies the current state if the height is different. */
    fun refreshStatusBarHeight()

    /** Adds the status bar view to the window manager. */
    fun attach()

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

    /** Returns the status bar window's background view. */
    val backgroundView: View

    /** Returns a fragment host manager for the status bar window view. */
    val fragmentHostManager: FragmentHostManager

    /**
     * Provides an updated animation controller if we're animating a view in the status bar.
     *
     * This is needed because we have to make sure that the status bar window matches the full
     * screen during the animation and that we are expanding the view below the other status bar
     * text.
     *
     * @param rootView the root view of the animation
     * @param animationController the default animation controller to use
     * @return If the animation is on a view in the status bar, returns an Optional containing an
     *   updated animation controller that handles status-bar-related animation details. Returns an
     *   empty optional if the animation is *not* on a view in the status bar.
     */
    fun wrapAnimationControllerIfInStatusBar(
        rootView: View,
        animationController: ActivityTransitionAnimator.Controller,
    ): Optional<ActivityTransitionAnimator.Controller>

    /** Set force status bar visible. */
    fun setForceStatusBarVisible(forceStatusBarVisible: Boolean)

    /**
     * Sets whether an ongoing process requires the status bar to be forced visible.
     *
     * This method is separate from {@link this#setForceStatusBarVisible} because the ongoing
     * process **takes priority**. For example, if {@link this#setForceStatusBarVisible} is set to
     * false but this method is set to true, then the status bar **will** be visible.
     *
     * TODO(b/195839150): We should likely merge this method and {@link
     *   this#setForceStatusBarVisible} together and use some sort of ranking system instead.
     */
    fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean)
}
+33 −51
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowManager;

import androidx.annotation.NonNull;

import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.animation.ActivityTransitionAnimator;
@@ -67,7 +69,7 @@ import javax.inject.Inject;
 * Encapsulates all logic for the status bar window state management.
 */
@SysUISingleton
public class StatusBarWindowController {
public class StatusBarWindowControllerImpl implements StatusBarWindowController {
    private static final String TAG = "StatusBarWindowController";
    private static final boolean DEBUG = false;

@@ -89,7 +91,7 @@ public class StatusBarWindowController {
    private final Binder mInsetsSourceOwner = new Binder();

    @Inject
    public StatusBarWindowController(
    public StatusBarWindowControllerImpl(
            Context context,
            @StatusBarWindowModule.InternalWindowView StatusBarWindowView statusBarWindowView,
            ViewCaptureAwareWindowManager viewCaptureAwareWindowManager,
@@ -117,14 +119,12 @@ public class StatusBarWindowController {
                                /* attachedViewProvider=*/ () -> mStatusBarWindowView)));
    }

    @Override
    public int getStatusBarHeight() {
        return mBarHeight;
    }

    /**
     * Rereads the status bar height and reapplys the current state if the height
     * is different.
     */
    @Override
    public void refreshStatusBarHeight() {
        Trace.beginSection("StatusBarWindowController#refreshStatusBarHeight");
        try {
@@ -141,9 +141,7 @@ public class StatusBarWindowController {
        }
    }

    /**
     * Adds the status bar view to the window manager.
     */
    @Override
    public void attach() {
        // Now that the status bar window encompasses the sliding panel and its
        // translucent backdrop, the entire thing is made TRANSLUCENT and is
@@ -161,42 +159,35 @@ public class StatusBarWindowController {
        apply(mCurrentState);
    }

    /** Adds the given view to the status bar window view. */
    public void addViewToWindow(View view, ViewGroup.LayoutParams layoutParams) {
    @Override
    public void addViewToWindow(@NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) {
        mStatusBarWindowView.addView(view, layoutParams);
    }

    /** Returns the status bar window's background view. */
    @NonNull
    @Override
    public View getBackgroundView() {
        return mStatusBarWindowView.findViewById(R.id.status_bar_container);
    }

    /** Returns a fragment host manager for the status bar window view. */
    @NonNull
    @Override
    public FragmentHostManager getFragmentHostManager() {
        return mFragmentService.getFragmentHostManager(mStatusBarWindowView);
    }

    /**
     * Provides an updated animation controller if we're animating a view in the status bar.
     *
     * This is needed because we have to make sure that the status bar window matches the full
     * screen during the animation and that we are expanding the view below the other status bar
     * text.
     *
     * @param rootView the root view of the animation
     * @param animationController the default animation controller to use
     * @return If the animation is on a view in the status bar, returns an Optional containing an
     *   updated animation controller that handles status-bar-related animation details. Returns an
     *   empty optional if the animation is *not* on a view in the status bar.
     */
    @NonNull
    @Override
    public Optional<ActivityTransitionAnimator.Controller> wrapAnimationControllerIfInStatusBar(
            View rootView, ActivityTransitionAnimator.Controller animationController) {
            @NonNull View rootView,
            @NonNull ActivityTransitionAnimator.Controller animationController) {
        if (rootView != mStatusBarWindowView) {
            return Optional.empty();
        }

        animationController.setTransitionContainer(mLaunchAnimationContainer);
        return Optional.of(new DelegateTransitionAnimatorController(animationController) {
        return Optional.of(
                new DelegateTransitionAnimatorController(animationController) {
                    @Override
                    public void onTransitionAnimationStart(boolean isExpandingFullyAbove) {
                        getDelegate().onTransitionAnimationStart(isExpandingFullyAbove);
@@ -275,22 +266,13 @@ public class StatusBarWindowController {
        }
    }

    /** Set force status bar visible. */
    @Override
    public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
        mCurrentState.mForceStatusBarVisible = forceStatusBarVisible;
        apply(mCurrentState);
    }

    /**
     * Sets whether an ongoing process requires the status bar to be forced visible.
     *
     * This method is separate from {@link this#setForceStatusBarVisible} because the ongoing
     * process **takes priority**. For example, if {@link this#setForceStatusBarVisible} is set to
     * false but this method is set to true, then the status bar **will** be visible.
     *
     * TODO(b/195839150): We should likely merge this method and
     * {@link this#setForceStatusBarVisible} together and use some sort of ranking system instead.
     */
    @Override
    public void setOngoingProcessRequiresStatusBarVisible(boolean visible) {
        mCurrentState.mOngoingProcessRequiresStatusBarVisible = visible;
        apply(mCurrentState);
+2 −2
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@ import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -504,7 +504,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
                mock(FragmentService.class),
                mLightBarController,
                mAutoHideController,
                new StatusBarInitializer(
                new StatusBarInitializerImpl(
                        mStatusBarWindowController,
                        mCollapsedStatusBarFragmentProvider,
                        emptySet()),