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

Commit 47e7a256 authored by Michael Mikhail's avatar Michael Mikhail
Browse files

[MEDIA TTT] Apply wakelock for chipbar

Starts new wakelock on start, then acquire wakelock when view is
displayed. And releases the wakelock if it is still held.

Bug: 241929425.
Test: ran adb command and checked the time while the screen is on. The
screen is on when the chipbar is displayed and goes off when the chipbar
is removed.
Test: atest MediaTttChipControllerReceiverTest.
Test: atest MediaTttSenderCoordinatorTest.
Test: atest TemporaryViewDisplayControllerTest.
Test: atest ChipbarCoordinatorTest.
Test: atest WakeLockTest.

Change-Id: I7a430df3689fe8d80bbcaf42ad165e789358ab8d
parent 3ce0aab5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.view.ViewUtil
import com.android.systemui.util.wakelock.WakeLock
import javax.inject.Inject

/**
@@ -68,6 +69,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
        private val mediaTttFlags: MediaTttFlags,
        private val uiEventLogger: MediaTttReceiverUiEventLogger,
        private val viewUtil: ViewUtil,
        wakeLockBuilder: WakeLock.Builder,
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>(
        context,
        logger,
@@ -77,6 +79,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
        configurationController,
        powerManager,
        R.layout.media_ttt_chip_receiver,
        wakeLockBuilder,
) {
    @SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
    override val windowLayoutParams = commonWindowLayoutParams.apply {
+27 −8
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.PowerManager
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -35,6 +34,7 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.wakelock.WakeLock

/**
 * A generic controller that can temporarily display a new view in a new window.
@@ -54,6 +54,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
    private val configurationController: ConfigurationController,
    private val powerManager: PowerManager,
    @LayoutRes private val viewLayoutRes: Int,
    private val wakeLockBuilder: WakeLock.Builder,
) : CoreStartable {
    /**
     * Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -64,7 +65,8 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
        height = WindowManager.LayoutParams.WRAP_CONTENT
        type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR
        flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
        format = PixelFormat.TRANSLUCENT
        setTrustedOverlay()
    }
@@ -83,6 +85,15 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
    /** A [Runnable] that, when run, will cancel the pending timeout of the view. */
    private var cancelViewTimeout: Runnable? = null

    /**
     * A wakelock that is acquired when view is displayed and screen off,
     * then released when view is removed.
     */
    private var wakeLock: WakeLock? = null

    /** A string that keeps track of wakelock reason once it is acquired till it gets released */
    private var wakeReasonAcquired: String? = null

    /**
     * Displays the view with the provided [newInfo].
     *
@@ -113,11 +124,15 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
            // the view to show over the dream state, so we should only wake up if the screen is
            // completely off.)
            if (!powerManager.isScreenOn) {
                powerManager.wakeUp(
                    SystemClock.uptimeMillis(),
                    PowerManager.WAKE_REASON_APPLICATION,
                    "com.android.systemui:${newInfo.wakeReason}",
                wakeLock = wakeLockBuilder
                    .setTag(newInfo.windowTitle)
                    .setLevelsAndFlags(
                        PowerManager.FULL_WAKE_LOCK or
                        PowerManager.ACQUIRE_CAUSES_WAKEUP
                    )
                    .build()
                wakeLock?.acquire(newInfo.wakeReason)
                wakeReasonAcquired = newInfo.wakeReason
            }
            logger.logViewAddition(newInfo.windowTitle)
            inflateAndUpdateView(newInfo)
@@ -155,6 +170,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
            it.copyFrom(windowLayoutParams)
            it.title = newInfo.windowTitle
        }
        newView.keepScreenOn = true
        windowManager.addView(newView, paramsWithTitle)
        animateViewIn(newView)
    }
@@ -183,7 +199,10 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
        val currentDisplayInfo = displayInfo ?: return

        val currentView = currentDisplayInfo.view
        animateViewOut(currentView) { windowManager.removeView(currentView) }
        animateViewOut(currentView) {
            windowManager.removeView(currentView)
            wakeLock?.release(wakeReasonAcquired)
        }

        logger.logViewRemoval(removalReason)
        configurationController.removeCallback(displayScaleListener)
+5 −2
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.view.ViewUtil
import com.android.systemui.util.wakelock.WakeLock
import javax.inject.Inject

/**
@@ -75,6 +76,7 @@ open class ChipbarCoordinator @Inject constructor(
        private val falsingCollector: FalsingCollector,
        private val viewUtil: ViewUtil,
        private val vibratorHelper: VibratorHelper,
        wakeLockBuilder: WakeLock.Builder,
) : TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>(
        context,
        logger,
@@ -84,6 +86,7 @@ open class ChipbarCoordinator @Inject constructor(
        configurationController,
        powerManager,
        R.layout.chipbar,
        wakeLockBuilder,
) {

    private lateinit var parent: ChipbarRootView
@@ -92,8 +95,6 @@ open class ChipbarCoordinator @Inject constructor(
        gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
    }

    override fun start() {}

    override fun updateView(
        newInfo: ChipbarInfo,
        currentView: ViewGroup
@@ -192,6 +193,8 @@ open class ChipbarCoordinator @Inject constructor(
        )
    }

    override fun start() {}

    override fun getTouchableRegion(view: View, outRect: Rect) {
        viewUtil.setRectToViewWindowLocation(view, outRect)
    }
+23 −4
Original line number Diff line number Diff line
@@ -37,6 +37,11 @@ public interface WakeLock {
     */
    long DEFAULT_MAX_TIMEOUT = 20000;

    /**
     * Default wake-lock levels and flags.
     */
    int DEFAULT_LEVELS_AND_FLAGS = PowerManager.PARTIAL_WAKE_LOCK;

    /**
     * @param why A tag that will be saved for sysui dumps.
     * @see android.os.PowerManager.WakeLock#acquire()
@@ -60,13 +65,21 @@ public interface WakeLock {
     * Creates a {@link WakeLock} that has a default release timeout.
     * @see android.os.PowerManager.WakeLock#acquire(long) */
    static WakeLock createPartial(Context context, String tag, long maxTimeout) {
        return wrap(createPartialInner(context, tag), maxTimeout);
        return wrap(createWakeLockInner(context, tag, DEFAULT_LEVELS_AND_FLAGS), maxTimeout);
    }

    /**
     * Creates a {@link WakeLock} that has a default release timeout and flags.
     */
    static WakeLock createWakeLock(Context context, String tag, int flags, long maxTimeout) {
        return wrap(createWakeLockInner(context, tag, flags), maxTimeout);
    }

    @VisibleForTesting
    static PowerManager.WakeLock createPartialInner(Context context, String tag) {
    static PowerManager.WakeLock createWakeLockInner(
            Context context, String tag, int levelsAndFlags) {
        return context.getSystemService(PowerManager.class)
                    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, tag);
                    .newWakeLock(levelsAndFlags, tag);
    }

    static Runnable wrapImpl(WakeLock w, Runnable r) {
@@ -131,6 +144,7 @@ public interface WakeLock {
    class Builder {
        private final Context mContext;
        private String mTag;
        private int mLevelsAndFlags = DEFAULT_LEVELS_AND_FLAGS;
        private long mMaxTimeout = DEFAULT_MAX_TIMEOUT;

        @Inject
@@ -143,13 +157,18 @@ public interface WakeLock {
            return this;
        }

        public Builder setLevelsAndFlags(int levelsAndFlags) {
            this.mLevelsAndFlags = levelsAndFlags;
            return this;
        }

        public Builder setMaxTimeout(long maxTimeout) {
            this.mMaxTimeout = maxTimeout;
            return this;
        }

        public WakeLock build() {
            return WakeLock.createPartial(mContext, mTag, mMaxTimeout);
            return WakeLock.createWakeLock(mContext, mTag, mLevelsAndFlags, mMaxTimeout);
        }
    }
}
+48 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.view.ViewUtil
import com.android.systemui.util.wakelock.WakeLockFake
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -85,6 +86,10 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
    private lateinit var fakeAppIconDrawable: Drawable
    private lateinit var uiEventLoggerFake: UiEventLoggerFake
    private lateinit var receiverUiEventLogger: MediaTttReceiverUiEventLogger
    private lateinit var fakeClock: FakeSystemClock
    private lateinit var fakeExecutor: FakeExecutor
    private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder
    private lateinit var fakeWakeLock: WakeLockFake

    @Before
    fun setUp() {
@@ -99,15 +104,22 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
        )).thenReturn(applicationInfo)
        context.setMockPackageManager(packageManager)

        fakeClock = FakeSystemClock()
        fakeExecutor = FakeExecutor(fakeClock)

        uiEventLoggerFake = UiEventLoggerFake()
        receiverUiEventLogger = MediaTttReceiverUiEventLogger(uiEventLoggerFake)

        fakeWakeLock = WakeLockFake()
        fakeWakeLockBuilder = WakeLockFake.Builder(context)
        fakeWakeLockBuilder.setWakeLock(fakeWakeLock)

        controllerReceiver = MediaTttChipControllerReceiver(
            commandQueue,
            context,
            logger,
            windowManager,
            FakeExecutor(FakeSystemClock()),
            fakeExecutor,
            accessibilityManager,
            configurationController,
            powerManager,
@@ -115,6 +127,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
            mediaTttFlags,
            receiverUiEventLogger,
            viewUtil,
            fakeWakeLockBuilder,
        )
        controllerReceiver.start()

@@ -141,6 +154,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
            mediaTttFlags,
            receiverUiEventLogger,
            viewUtil,
            fakeWakeLockBuilder,
        )
        controllerReceiver.start()

@@ -199,6 +213,39 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
        verify(windowManager).removeView(viewCaptor.value)
    }

    @Test
    fun commandQueueCallback_closeThenFar_wakeLockAcquiredThenReleased() {
        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
                StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
                routeInfo,
                null,
                null
        )

        assertThat(fakeWakeLock.isHeld).isTrue()

        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
                StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
                routeInfo,
                null,
                null
        )

        assertThat(fakeWakeLock.isHeld).isFalse()
    }

    @Test
    fun commandQueueCallback_closeThenFar_wakeLockNeverAcquired() {
        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
                StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
                routeInfo,
                null,
                null
        )

        assertThat(fakeWakeLock.isHeld).isFalse()
    }

    @Test
    fun receivesNewStateFromCommandQueue_isLogged() {
        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
Loading