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

Commit 7236cad9 authored by Steve Elliott's avatar Steve Elliott
Browse files

NotificationShelf ViewBinder + WrapperController

This new implementation is a fork of the existing implementation, but
converted to Kotlin. It is functionally identical, but sets the stage
for a transition to a ViewBinder as a replacement for the
NotificationShelfController.

Bug: 271161129
Test: atest SystemUITests
Change-Id: Ica1acf70e001353b1b24d3d53c6de02ad217079d
parent d58af8ca
Loading
Loading
Loading
Loading
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.notification.shelf.view

import android.view.View
import android.view.View.OnAttachStateChangeListener
import android.view.accessibility.AccessibilityManager
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.NotificationShelfController
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController
import com.android.systemui.statusbar.notification.row.ExpandableOutlineViewController
import com.android.systemui.statusbar.notification.row.ExpandableViewController
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.phone.NotificationTapHelper
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import dagger.Binds
import dagger.Module
import javax.inject.Inject

/** Binds a [NotificationShelf] to its backend. */
interface NotificationShelfViewBinder {
    fun bind(shelf: NotificationShelf)
}

/**
 * Controller class for [NotificationShelf]. This implementation serves as a temporary wrapper
 * around a [NotificationShelfViewBinder], so that external code can continue to depend on the
 * [NotificationShelfController] interface. Once the [LegacyNotificationShelfControllerImpl] is
 * removed, this class can go away and the ViewBinder can be used directly.
 */
@CentralSurfacesScope
class NotificationShelfViewBinderWrapperControllerImpl
@Inject
constructor(
    private val shelf: NotificationShelf,
    private val viewBinder: NotificationShelfViewBinder,
    private val keyguardBypassController: KeyguardBypassController,
    featureFlags: FeatureFlags,
    private val notifTapHelperFactory: NotificationTapHelper.Factory,
    private val a11yManager: AccessibilityManager,
    private val falsingManager: FalsingManager,
    private val falsingCollector: FalsingCollector,
    private val statusBarStateController: SysuiStatusBarStateController,
) : NotificationShelfController {

    private var ambientState: AmbientState? = null

    override val view: NotificationShelf
        get() = shelf

    init {
        shelf.apply {
            useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES))
            setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM))
        }
    }

    fun init() {
        viewBinder.bind(shelf)

        ActivatableNotificationViewController(
                shelf,
                notifTapHelperFactory,
                ExpandableOutlineViewController(shelf, ExpandableViewController(shelf)),
                a11yManager,
                falsingManager,
                falsingCollector,
            )
            .init()
        shelf.setController(this)
        val onAttachStateListener =
            object : OnAttachStateChangeListener {
                override fun onViewAttachedToWindow(v: View) {
                    statusBarStateController.addCallback(
                        shelf,
                        SysuiStatusBarStateController.RANK_SHELF,
                    )
                }

                override fun onViewDetachedFromWindow(v: View) {
                    statusBarStateController.removeCallback(shelf)
                }
            }
        shelf.addOnAttachStateChangeListener(onAttachStateListener)
        if (shelf.isAttachedToWindow) {
            onAttachStateListener.onViewAttachedToWindow(shelf)
        }
    }

    override val intrinsicHeight: Int
        get() = shelf.intrinsicHeight

    override val shelfIcons: NotificationIconContainer
        get() = shelf.shelfIcons

    override fun canModifyColorOfNotifications(): Boolean {
        return (ambientState?.isShadeExpanded == true &&
            !(ambientState?.isOnKeyguard == true && keyguardBypassController.bypassEnabled))
    }

    override fun setOnActivatedListener(listener: ActivatableNotificationView.OnActivatedListener) {
        shelf.setOnActivatedListener(listener)
    }

    override fun bind(
        ambientState: AmbientState,
        notificationStackScrollLayoutController: NotificationStackScrollLayoutController
    ) {
        shelf.bind(ambientState, notificationStackScrollLayoutController)
        this.ambientState = ambientState
    }

    override fun setOnClickListener(listener: View.OnClickListener) {
        shelf.setOnClickListener(listener)
    }
}

@Module(includes = [PrivateShelfViewBinderModule::class]) object NotificationShelfViewBinderModule

@Module
private interface PrivateShelfViewBinderModule {
    @Binds fun bindImpl(impl: NotificationShelfViewBinderImpl): NotificationShelfViewBinder
}

@CentralSurfacesScope
private class NotificationShelfViewBinderImpl @Inject constructor() : NotificationShelfViewBinder {
    override fun bind(shelf: NotificationShelf) {}
}
+22 −9
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.systemui.biometrics.AuthRippleView;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.privacy.OngoingPrivacyChip;
import com.android.systemui.settings.UserTracker;
@@ -51,6 +52,8 @@ import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.notification.shelf.view.NotificationShelfViewBinderModule;
import com.android.systemui.statusbar.notification.shelf.view.NotificationShelfViewBinderWrapperControllerImpl;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.LetterboxAppearanceCalculator;
@@ -77,13 +80,15 @@ import com.android.systemui.util.settings.SecureSettings;
import java.util.concurrent.Executor;

import javax.inject.Named;
import javax.inject.Provider;

import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;

@Module(subcomponents = StatusBarFragmentComponent.class)
@Module(subcomponents = StatusBarFragmentComponent.class,
        includes = { NotificationShelfViewBinderModule.class })
public abstract class StatusBarViewModule {

    public static final String SHADE_HEADER = "large_screen_shade_header";
@@ -131,8 +136,15 @@ public abstract class StatusBarViewModule {
    @Provides
    @CentralSurfacesComponent.CentralSurfacesScope
    public static NotificationShelfController providesStatusBarWindowView(
            FeatureFlags featureFlags,
            Provider<NotificationShelfViewBinderWrapperControllerImpl> newImpl,
            NotificationShelfComponent.Builder notificationShelfComponentBuilder,
            NotificationShelf notificationShelf) {
        if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
            NotificationShelfViewBinderWrapperControllerImpl impl = newImpl.get();
            impl.init();
            return impl;
        } else {
            NotificationShelfComponent component = notificationShelfComponentBuilder
                    .notificationShelf(notificationShelf)
                    .build();
@@ -142,6 +154,7 @@ public abstract class StatusBarViewModule {

            return notificationShelfController;
        }
    }

    /** */
    @Provides