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

Commit c3523d65 authored by Bryce Lee's avatar Bryce Lee Committed by Android (Google) Code Review
Browse files

Merge "Convert DreamOverlayStateController to Kotlin." into main

parents 4d9fc173 de527e5d
Loading
Loading
Loading
Loading
+24 −25
Original line number Diff line number Diff line
@@ -90,7 +90,6 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
@@ -281,9 +280,9 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
            val overlay = IDreamOverlay.Stub.asInterface(proxy)
            val callback = Mockito.mock(IDreamOverlayClientCallback::class.java)
            overlay.getClient(callback)
            val clientCaptor = ArgumentCaptor.forClass(IDreamOverlayClient::class.java)
            val clientCaptor = argumentCaptor<IDreamOverlayClient>()
            verify(callback).onDreamOverlayClient(clientCaptor.capture())
            return clientCaptor.value
            return clientCaptor.lastValue
        }

    @Test
@@ -338,10 +337,10 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        )
        mMainExecutor.runAllReady()
        verify(mWindowManager).addView(any(), any())
        verify(mStateController).setOverlayActive(false)
        verify(mStateController).setLowLightActive(false)
        verify(mStateController).isOverlayActive = false
        verify(mStateController).isLowLightActive = false
        verify(mStateController).setEntryAnimationsFinished(false)
        verify(mStateController, never()).setOverlayActive(true)
        verify(mStateController, never()).isOverlayActive = true
        verify(mUiEventLogger, never())
            .log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START)
        verify(mDreamOverlayCallbackController, never()).onStartDream()
@@ -428,12 +427,12 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {

        verifyNoMoreInteractions(mTouchMonitor)

        val captor = ArgumentCaptor.forClass(DreamOverlayStateController.Callback::class.java)
        val captor = argumentCaptor<DreamOverlayStateController.Callback>()
        verify(mStateController).addCallback(captor.capture())

        whenever(mStateController.areExitAnimationsRunning()).thenReturn(false)

        captor.firstValue.onStateChanged()
        captor.lastValue.onStateChanged()

        // Should only be called once since it should be null during the second reset.
        verify(mTouchMonitor).destroy()
@@ -453,7 +452,7 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        )
        mMainExecutor.runAllReady()
        assertThat(mService.dreamComponent).isEqualTo(LOW_LIGHT_COMPONENT)
        verify(mStateController).setLowLightActive(true)
        verify(mStateController).isLowLightActive = true
    }

    @Test
@@ -498,8 +497,8 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        verify(mWindowManager).removeView(mViewCaptor.firstValue)

        // Verify state correctly set.
        verify(mStateController).setOverlayActive(false)
        verify(mStateController).setLowLightActive(false)
        verify(mStateController).isOverlayActive = false
        verify(mStateController).isLowLightActive = false
        verify(mStateController).setEntryAnimationsFinished(false)

        // Verify touch monitor destroyed
@@ -542,7 +541,7 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
                null
            }
            .`when`(mStateController)
            .setOverlayActive(true)
            .isOverlayActive = true

        // Start the dream.
        client.startDream(
@@ -587,8 +586,8 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        // Verify state correctly set.
        verify(mKeyguardUpdateMonitor).removeCallback(any())
        assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.DESTROYED)
        verify(mStateController).setOverlayActive(false)
        verify(mStateController).setLowLightActive(false)
        verify(mStateController).isOverlayActive = false
        verify(mStateController).isLowLightActive = false
        verify(mStateController).setEntryAnimationsFinished(false)
    }

@@ -604,8 +603,8 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        // Verify state still correctly set.
        verify(mKeyguardUpdateMonitor).removeCallback(any())
        assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.DESTROYED)
        verify(mStateController).setOverlayActive(false)
        verify(mStateController).setLowLightActive(false)
        verify(mStateController).isOverlayActive = false
        verify(mStateController).isLowLightActive = false
    }

    @Test
@@ -727,12 +726,12 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
            false, /*shouldShowComplication*/
        )
        mMainExecutor.runAllReady()
        val paramsCaptor = ArgumentCaptor.forClass(WindowManager.LayoutParams::class.java)
        val paramsCaptor = argumentCaptor<WindowManager.LayoutParams>()

        // Verify that a new window is added.
        verify(mWindowManager).addView(any(), paramsCaptor.capture())
        assertThat(
                paramsCaptor.value.privateFlags and
                paramsCaptor.lastValue.privateFlags and
                    WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS ==
                    WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS
            )
@@ -1000,18 +999,18 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        )
        mMainExecutor.runAllReady()
        assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.RESUMED)
        val callbackCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
        val callbackCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
        verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture())

        // Notification shade opens.
        callbackCaptor.value.onShadeExpandedChanged(true)
        callbackCaptor.lastValue.onShadeExpandedChanged(true)
        mMainExecutor.runAllReady()

        // Lifecycle state goes from resumed back to started when the notification shade shows.
        assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.STARTED)

        // Notification shade closes.
        callbackCaptor.value.onShadeExpandedChanged(false)
        callbackCaptor.lastValue.onShadeExpandedChanged(false)
        mMainExecutor.runAllReady()

        // Lifecycle state goes back to RESUMED.
@@ -1228,11 +1227,11 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        val dreamTaskInfo = TaskInfo(mock<ComponentName>(), WindowConfiguration.ACTIVITY_TYPE_DREAM)
        assertThat(matcher.matches(dreamTaskInfo)).isTrue()

        val callbackCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
        val callbackCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
        verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture())

        // Notification shade opens.
        callbackCaptor.value.onShadeExpandedChanged(true)
        callbackCaptor.lastValue.onShadeExpandedChanged(true)
        mMainExecutor.runAllReady()

        verify(gestureInteractor)
@@ -1265,11 +1264,11 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
        mMainExecutor.runAllReady()
        clearInvocations(gestureInteractor)

        val callbackCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
        val callbackCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
        verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture())

        // Notification shade opens.
        callbackCaptor.value.onShadeExpandedChanged(true)
        callbackCaptor.lastValue.onShadeExpandedChanged(true)
        mMainExecutor.runAllReady()

        verify(gestureInteractor)
+0 −448
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.dreams;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.complication.Complication;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.FakeLogBuffer;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.reference.FakeWeakReferenceFactory;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.Collection;

@SmallTest
@RunWith(AndroidJUnit4.class)
@android.platform.test.annotations.EnabledOnRavenwood
public class DreamOverlayStateControllerTest extends SysuiTestCase {
    @Mock
    DreamOverlayStateController.Callback mCallback;

    @Mock
    Complication mComplication;

    @Mock
    private FeatureFlags mFeatureFlags;

    private final LogBuffer mLogBuffer = FakeLogBuffer.Factory.Companion.create();

    final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());

    final FakeWeakReferenceFactory mWeakReferenceFactory = new FakeWeakReferenceFactory();

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

        when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(false);
    }

    @Test
    public void testStateChange_overlayActive() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.addCallback(mCallback);
        stateController.setOverlayActive(true);
        mExecutor.runAllReady();

        verify(mCallback).onStateChanged();
        assertThat(stateController.isOverlayActive()).isTrue();

        Mockito.clearInvocations(mCallback);
        stateController.setOverlayActive(true);
        mExecutor.runAllReady();
        verify(mCallback, never()).onStateChanged();

        stateController.setOverlayActive(false);
        mExecutor.runAllReady();
        verify(mCallback).onStateChanged();
        assertThat(stateController.isOverlayActive()).isFalse();
    }

    @Test
    public void testCallback() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.addCallback(mCallback);

        // Add complication and verify callback is notified.
        stateController.addComplication(mComplication);

        mExecutor.runAllReady();

        verify(mCallback, times(1)).onComplicationsChanged();

        final Collection<Complication> complications = stateController.getComplications();
        assertEquals(complications.size(), 1);
        assertTrue(complications.contains(mComplication));

        clearInvocations(mCallback);

        // Remove complication and verify callback is notified.
        stateController.removeComplication(mComplication);
        mExecutor.runAllReady();
        verify(mCallback, times(1)).onComplicationsChanged();
        assertTrue(stateController.getComplications().isEmpty());
    }

    @Test
    public void testNotifyOnCallbackAdd() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        stateController.addComplication(mComplication);
        mExecutor.runAllReady();

        // Verify callback occurs on add when an overlay is already present.
        stateController.addCallback(mCallback);
        mExecutor.runAllReady();
        verify(mCallback, times(1)).onComplicationsChanged();
    }

    @Test
    public void testComplicationFilteringWhenShouldShowComplications() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.setShouldShowComplications(true);

        final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
        final Complication weatherComplication = Mockito.mock(Complication.class);
        when(alwaysAvailableComplication.getRequiredTypeAvailability())
                .thenReturn(Complication.COMPLICATION_TYPE_NONE);
        when(weatherComplication.getRequiredTypeAvailability())
                .thenReturn(Complication.COMPLICATION_TYPE_WEATHER);

        stateController.addComplication(alwaysAvailableComplication);
        stateController.addComplication(weatherComplication);

        final DreamOverlayStateController.Callback callback =
                Mockito.mock(DreamOverlayStateController.Callback.class);

        stateController.addCallback(callback);
        mExecutor.runAllReady();

        {
            final Collection<Complication> complications = stateController.getComplications();
            assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
            assertThat(complications.contains(weatherComplication)).isFalse();
        }

        stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_WEATHER);
        mExecutor.runAllReady();
        verify(callback).onAvailableComplicationTypesChanged();

        {
            final Collection<Complication> complications = stateController.getComplications();
            assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
            assertThat(complications.contains(weatherComplication)).isTrue();
        }

    }

    @Test
    public void testComplicationFilteringWhenShouldHideComplications() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.setShouldShowComplications(true);

        final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
        final Complication weatherComplication = Mockito.mock(Complication.class);
        when(alwaysAvailableComplication.getRequiredTypeAvailability())
                .thenReturn(Complication.COMPLICATION_TYPE_NONE);
        when(weatherComplication.getRequiredTypeAvailability())
                .thenReturn(Complication.COMPLICATION_TYPE_WEATHER);

        stateController.addComplication(alwaysAvailableComplication);
        stateController.addComplication(weatherComplication);

        final DreamOverlayStateController.Callback callback =
                Mockito.mock(DreamOverlayStateController.Callback.class);

        stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_WEATHER);
        stateController.addCallback(callback);
        mExecutor.runAllReady();

        {
            clearInvocations(callback);
            stateController.setShouldShowComplications(true);
            mExecutor.runAllReady();

            verify(callback).onAvailableComplicationTypesChanged();
            final Collection<Complication> complications = stateController.getComplications();
            assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
            assertThat(complications.contains(weatherComplication)).isTrue();
        }

        {
            clearInvocations(callback);
            stateController.setShouldShowComplications(false);
            mExecutor.runAllReady();

            verify(callback).onAvailableComplicationTypesChanged();
            final Collection<Complication> complications = stateController.getComplications();
            assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
            assertThat(complications.contains(weatherComplication)).isFalse();
        }
    }

    @Test
    public void testComplicationWithNoTypeNotFiltered() {
        final Complication complication = Mockito.mock(Complication.class);
        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.addComplication(complication);
        mExecutor.runAllReady();
        assertThat(stateController.getComplications(true).contains(complication))
                .isTrue();
    }

    @Test
    public void testComplicationsNotShownForHomeControlPanelDream() {
        final Complication complication = Mockito.mock(Complication.class);
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        // Add a complication and verify it's returned in getComplications.
        stateController.addComplication(complication);
        mExecutor.runAllReady();
        assertThat(stateController.getComplications().contains(complication))
                .isTrue();

        stateController.setHomeControlPanelActive(true);
        mExecutor.runAllReady();

        assertThat(stateController.getComplications()).isEmpty();
    }

    @Test
    public void testComplicationsNotShownForLowLight() {
        final Complication complication = Mockito.mock(Complication.class);
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        // Add a complication and verify it's returned in getComplications.
        stateController.addComplication(complication);
        mExecutor.runAllReady();
        assertThat(stateController.getComplications().contains(complication))
                .isTrue();

        stateController.setLowLightActive(true);
        mExecutor.runAllReady();

        assertThat(stateController.getComplications()).isEmpty();
    }

    @Test
    public void testNotifyLowLightChanged() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        stateController.addCallback(mCallback);
        mExecutor.runAllReady();
        assertThat(stateController.isLowLightActive()).isFalse();

        stateController.setLowLightActive(true);

        mExecutor.runAllReady();
        verify(mCallback, times(1)).onStateChanged();
        assertThat(stateController.isLowLightActive()).isTrue();
    }

    @Test
    public void testNotifyLowLightExit() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        stateController.addCallback(mCallback);
        mExecutor.runAllReady();
        assertThat(stateController.isLowLightActive()).isFalse();

        // Turn low light on then off to trigger the exiting callback.
        stateController.setLowLightActive(true);
        stateController.setLowLightActive(false);

        // Callback was only called once, when
        mExecutor.runAllReady();
        verify(mCallback, times(1)).onExitLowLight();
        assertThat(stateController.isLowLightActive()).isFalse();

        // Set with false again, which should not cause the callback to trigger again.
        stateController.setLowLightActive(false);
        mExecutor.runAllReady();
        verify(mCallback, times(1)).onExitLowLight();
    }

    @Test
    public void testNotifyEntryAnimationsFinishedChanged() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        stateController.addCallback(mCallback);
        mExecutor.runAllReady();
        assertThat(stateController.areEntryAnimationsFinished()).isFalse();

        stateController.setEntryAnimationsFinished(true);
        mExecutor.runAllReady();

        verify(mCallback, times(1)).onStateChanged();
        assertThat(stateController.areEntryAnimationsFinished()).isTrue();
    }

    @Test
    public void testNotifyDreamOverlayStatusBarVisibleChanged() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        stateController.addCallback(mCallback);
        mExecutor.runAllReady();
        assertThat(stateController.isDreamOverlayStatusBarVisible()).isFalse();

        stateController.setDreamOverlayStatusBarVisible(true);
        mExecutor.runAllReady();

        verify(mCallback, times(1)).onStateChanged();
        assertThat(stateController.isDreamOverlayStatusBarVisible()).isTrue();
    }

    @Test
    public void testNotifyHasAssistantAttentionChanged() {
        final DreamOverlayStateController stateController = getDreamOverlayStateController();

        stateController.addCallback(mCallback);
        mExecutor.runAllReady();
        assertThat(stateController.hasAssistantAttention()).isFalse();

        stateController.setHasAssistantAttention(true);
        mExecutor.runAllReady();

        verify(mCallback, times(1)).onStateChanged();
        assertThat(stateController.hasAssistantAttention()).isTrue();
    }

    @Test
    public void testShouldShowComplicationsSetToFalse_stillShowsHomeControls_featureEnabled() {
        when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true);

        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.setShouldShowComplications(true);

        final Complication homeControlsComplication = Mockito.mock(Complication.class);
        when(homeControlsComplication.getRequiredTypeAvailability())
                .thenReturn(Complication.COMPLICATION_TYPE_HOME_CONTROLS);

        stateController.addComplication(homeControlsComplication);

        final DreamOverlayStateController.Callback callback =
                Mockito.mock(DreamOverlayStateController.Callback.class);

        stateController.setAvailableComplicationTypes(
                Complication.COMPLICATION_TYPE_HOME_CONTROLS);
        stateController.addCallback(callback);
        mExecutor.runAllReady();

        {
            clearInvocations(callback);
            stateController.setShouldShowComplications(true);
            mExecutor.runAllReady();

            verify(callback).onAvailableComplicationTypesChanged();
            final Collection<Complication> complications = stateController.getComplications();
            assertThat(complications.contains(homeControlsComplication)).isTrue();
        }

        {
            clearInvocations(callback);
            stateController.setShouldShowComplications(false);
            mExecutor.runAllReady();

            verify(callback).onAvailableComplicationTypesChanged();
            final Collection<Complication> complications = stateController.getComplications();
            assertThat(complications.contains(homeControlsComplication)).isTrue();
        }
    }

    @Test
    public void testHomeControlsDoNotShowIfNotAvailable_featureEnabled() {
        when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true);

        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.setShouldShowComplications(true);

        final Complication homeControlsComplication = Mockito.mock(Complication.class);
        when(homeControlsComplication.getRequiredTypeAvailability())
                .thenReturn(Complication.COMPLICATION_TYPE_HOME_CONTROLS);

        stateController.addComplication(homeControlsComplication);

        final DreamOverlayStateController.Callback callback =
                Mockito.mock(DreamOverlayStateController.Callback.class);

        stateController.addCallback(callback);
        mExecutor.runAllReady();

        // No home controls since it is not available.
        assertThat(stateController.getComplications()).doesNotContain(homeControlsComplication);

        stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_HOME_CONTROLS
                | Complication.COMPLICATION_TYPE_WEATHER);
        mExecutor.runAllReady();
        assertThat(stateController.getComplications()).contains(homeControlsComplication);
    }

    @Test
    public void testCallbacksIgnoredWhenWeakReferenceCleared() {
        final DreamOverlayStateController.Callback callback1 = Mockito.mock(
                DreamOverlayStateController.Callback.class);
        final DreamOverlayStateController.Callback callback2 = Mockito.mock(
                DreamOverlayStateController.Callback.class);

        final DreamOverlayStateController stateController = getDreamOverlayStateController();
        stateController.addCallback(callback1);
        stateController.addCallback(callback2);
        mExecutor.runAllReady();

        // Simulate callback1 getting GC'd by clearing the reference
        mWeakReferenceFactory.clear(callback1);
        stateController.setOverlayActive(true);
        mExecutor.runAllReady();

        // Callback2 should still be called, but never callback1
        verify(callback1, never()).onStateChanged();
        verify(callback2).onStateChanged();
        assertThat(stateController.isOverlayActive()).isTrue();
    }

    private DreamOverlayStateController getDreamOverlayStateController() {
        return new DreamOverlayStateController(
                mExecutor,
                mFeatureFlags,
                mLogBuffer,
                mWeakReferenceFactory
        );
    }
}
+355 −0

File added.

Preview size limit exceeded, changes collapsed.

+0 −417

File deleted.

Preview size limit exceeded, changes collapsed.

+386 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading