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

Commit 6bfab8f7 authored by Lucas Dupin's avatar Lucas Dupin Committed by Android (Google) Code Review
Browse files

Merge "Always destroy RegionSamplingHelper on same thread"

parents 739eaf1c dafd01de
Loading
Loading
Loading
Loading
+39 −7
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ import android.view.View;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;

import androidx.annotation.VisibleForTesting;

import java.io.PrintWriter;
import java.util.concurrent.Executor;

@@ -60,6 +62,7 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener,
    private final Rect mRegisteredSamplingBounds = new Rect();
    private final SamplingCallback mCallback;
    private final Executor mBackgroundExecutor;
    private final SysuiCompositionSamplingListener mCompositionSamplingListener;
    private boolean mSamplingEnabled = false;
    private boolean mSamplingListenerRegistered = false;

@@ -91,9 +94,17 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener,

    public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback,
            Executor backgroundExecutor) {
        this(sampledView, samplingCallback, sampledView.getContext().getMainExecutor(),
                backgroundExecutor, new SysuiCompositionSamplingListener());
    }

    @VisibleForTesting
    RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback,
            Executor mainExecutor, Executor backgroundExecutor,
            SysuiCompositionSamplingListener compositionSamplingListener) {
        mBackgroundExecutor = backgroundExecutor;
        mSamplingListener = new CompositionSamplingListener(
                sampledView.getContext().getMainExecutor()) {
        mCompositionSamplingListener = compositionSamplingListener;
        mSamplingListener = new CompositionSamplingListener(mainExecutor) {
            @Override
            public void onSampleCollected(float medianLuma) {
                if (mSamplingEnabled) {
@@ -136,7 +147,7 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener,

    public void stopAndDestroy() {
        stop();
        mSamplingListener.destroy();
        mBackgroundExecutor.execute(mSamplingListener::destroy);
        mIsDestroyed = true;
    }

@@ -189,13 +200,12 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener,
                // We only want to re-register if something actually changed
                unregisterSamplingListener();
                mSamplingListenerRegistered = true;
                SurfaceControl wrappedStopLayer = stopLayerControl == null
                        ? null : new SurfaceControl(stopLayerControl, "regionSampling");
                SurfaceControl wrappedStopLayer = wrap(stopLayerControl);
                mBackgroundExecutor.execute(() -> {
                    if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) {
                        return;
                    }
                    CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
                    mCompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
                            wrappedStopLayer, mSamplingRequestBounds);
                });
                mRegisteredSamplingBounds.set(mSamplingRequestBounds);
@@ -208,14 +218,21 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener,
        }
    }

    @VisibleForTesting
    protected SurfaceControl wrap(SurfaceControl stopLayerControl) {
        return stopLayerControl == null ? null : new SurfaceControl(stopLayerControl,
                "regionSampling");
    }

    private void unregisterSamplingListener() {
        if (mSamplingListenerRegistered) {
            mSamplingListenerRegistered = false;
            SurfaceControl wrappedStopLayer = mWrappedStopLayer;
            mRegisteredStopLayer = null;
            mWrappedStopLayer = null;
            mRegisteredSamplingBounds.setEmpty();
            mBackgroundExecutor.execute(() -> {
                CompositionSamplingListener.unregister(mSamplingListener);
                mCompositionSamplingListener.unregister(mSamplingListener);
                if (wrappedStopLayer != null && wrappedStopLayer.isValid()) {
                    wrappedStopLayer.release();
                }
@@ -299,4 +316,19 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener,
            return true;
        }
    }

    @VisibleForTesting
    public static class SysuiCompositionSamplingListener {
        public void register(CompositionSamplingListener listener,
                int displayId, SurfaceControl stopLayer, Rect samplingArea) {
            CompositionSamplingListener.register(listener, displayId, stopLayer, samplingArea);
        }

        /**
         * Unregisters a sampling listener.
         */
        public void unregister(CompositionSamplingListener listener) {
            CompositionSamplingListener.unregister(listener);
        }
    }
}
+102 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.shared.navigationbar
import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.SurfaceControl
import android.view.View
import android.view.ViewRootImpl
import androidx.concurrent.futures.DirectExecutor
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever

@RunWith(AndroidTestingRunner::class)
@SmallTest
@RunWithLooper
class RegionSamplingHelperTest : SysuiTestCase() {

    @Mock
    lateinit var sampledView: View
    @Mock
    lateinit var samplingCallback: RegionSamplingHelper.SamplingCallback
    @Mock
    lateinit var compositionListener: RegionSamplingHelper.SysuiCompositionSamplingListener
    @Mock
    lateinit var viewRootImpl: ViewRootImpl
    @Mock
    lateinit var surfaceControl: SurfaceControl
    @Mock
    lateinit var wrappedSurfaceControl: SurfaceControl
    @JvmField @Rule
    var rule = MockitoJUnit.rule()
    lateinit var regionSamplingHelper: RegionSamplingHelper

    @Before
    fun setup() {
        whenever(sampledView.isAttachedToWindow).thenReturn(true)
        whenever(sampledView.viewRootImpl).thenReturn(viewRootImpl)
        whenever(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
        whenever(surfaceControl.isValid).thenReturn(true)
        whenever(wrappedSurfaceControl.isValid).thenReturn(true)
        whenever(samplingCallback.isSamplingEnabled).thenReturn(true)
        regionSamplingHelper = object : RegionSamplingHelper(sampledView, samplingCallback,
                DirectExecutor.INSTANCE, DirectExecutor.INSTANCE, compositionListener) {
            override fun wrap(stopLayerControl: SurfaceControl?): SurfaceControl {
                return wrappedSurfaceControl
            }
        }
        regionSamplingHelper.setWindowVisible(true)
    }

    @Test
    fun testStart_register() {
        regionSamplingHelper.start(Rect(0, 0, 100, 100))
        verify(compositionListener).register(any(), anyInt(), eq(wrappedSurfaceControl), any())
    }

    @Test
    fun testStart_unregister() {
        regionSamplingHelper.start(Rect(0, 0, 100, 100))
        regionSamplingHelper.setWindowVisible(false)
        verify(compositionListener).unregister(any())
    }

    @Test
    fun testStart_hasBlur_neverRegisters() {
        regionSamplingHelper.setWindowHasBlurs(true)
        regionSamplingHelper.start(Rect(0, 0, 100, 100))
        verify(compositionListener, never())
                .register(any(), anyInt(), eq(wrappedSurfaceControl), any())
    }

    @Test
    fun testStart_stopAndDestroy() {
        regionSamplingHelper.start(Rect(0, 0, 100, 100))
        regionSamplingHelper.stopAndDestroy()
        verify(compositionListener).unregister(any())
    }
}
 No newline at end of file