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

Commit 162f7218 authored by Bryce Lee's avatar Bryce Lee
Browse files

Do not show communal view when occluded.

This change hides the communal view when the bouncer
is shown on screen or the keyguard is otherwise
occluded.

Bug: 195126279
Test: atest CommunalHostViewControllerTest#testHideOnBouncer
Change-Id: Ib2e177f49f563d541aae57e9bfbf2b3ea4b60776
parent 8600c8e9
Loading
Loading
Loading
Loading
+80 −9
Original line number Diff line number Diff line
@@ -16,20 +16,23 @@

package com.android.systemui.communal;

import android.annotation.IntDef;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;

import com.google.common.util.concurrent.ListenableFuture;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.concurrent.Executor;

@@ -40,22 +43,50 @@ import javax.inject.Inject;
 */
public class CommunalHostViewController extends ViewController<CommunalHostView> {
    private static final String TAG = "CommunalController";
    private static final boolean DEBUG = false;
    private static final AnimationProperties ANIMATION_PROPERTIES =
            new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    private static final String STATE_LIST_FORMAT = "[%s]";

    private final Executor mMainExecutor;
    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    private final KeyguardStateController mKeyguardStateController;
    private final StatusBarStateController mStatusBarStateController;
    private WeakReference<CommunalSource> mLastSource;
    private int mState;

    @Retention(RetentionPolicy.RUNTIME)
    @IntDef({STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_BOUNCER_SHOWING, STATE_KEYGUARD_OCCLUDED})
    public @interface State {}

    private static final int STATE_KEYGUARD_SHOWING = 1 << 0;
    private static final int STATE_DOZING = 1 << 1;
    private static final int STATE_BOUNCER_SHOWING = 1 << 2;
    private static final int STATE_KEYGUARD_OCCLUDED = 1 << 3;

    // Only show communal view when keyguard is showing and not dozing.
    private static final int SHOW_COMMUNAL_VIEW_REQUIRED_STATES = STATE_KEYGUARD_SHOWING;
    private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES = STATE_DOZING;
    private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES =
            STATE_DOZING | STATE_BOUNCER_SHOWING | STATE_KEYGUARD_OCCLUDED;

    private KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
            new KeyguardUpdateMonitorCallback() {
                @Override
                public void onKeyguardBouncerChanged(boolean bouncer) {
                    if (DEBUG) {
                        Log.d(TAG, "onKeyguardBouncerChanged:" + bouncer);
                    }

                    setState(STATE_BOUNCER_SHOWING, bouncer);
                }

                @Override
                public void onKeyguardOccludedChanged(boolean occluded) {
                    if (DEBUG) {
                        Log.d(TAG, "onKeyguardOccludedChanged" + occluded);
                    }

                    setState(STATE_KEYGUARD_OCCLUDED, occluded);
                }
            };

    private KeyguardStateController.Callback mKeyguardCallback =
            new KeyguardStateController.Callback() {
@@ -84,9 +115,11 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>

    @Inject
    protected CommunalHostViewController(@Main Executor mainExecutor,
            KeyguardUpdateMonitor keyguardUpdateMonitor,
            KeyguardStateController keyguardStateController,
            StatusBarStateController statusBarStateController, CommunalHostView view) {
        super(view);
        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
        mMainExecutor = mainExecutor;
        mKeyguardStateController = keyguardStateController;
        mStatusBarStateController = statusBarStateController;
@@ -104,18 +137,20 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>
    protected void onViewAttached() {
        mKeyguardStateController.addCallback(mKeyguardCallback);
        mStatusBarStateController.addCallback(mDozeCallback);
        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
    }

    @Override
    protected void onViewDetached() {
        mKeyguardStateController.removeCallback(mKeyguardCallback);
        mStatusBarStateController.removeCallback(mDozeCallback);
        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
    }

    private void setState(int stateFlag, boolean enabled) {
    private void setState(@State int stateFlag, boolean enabled) {
        final int existingState = mState;
        if (DEBUG) {
            Log.d(TAG, "setState flag:" + stateFlag + " enabled:" + enabled);
            Log.d(TAG, "setState flag:" + describeState(stateFlag) + " enabled:" + enabled);
        }

        if (enabled) {
@@ -125,7 +160,7 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>
        }

        if (DEBUG) {
            Log.d(TAG, "updated state:" + mState);
            Log.d(TAG, "updated state:" + describeState());
        }

        if (existingState != mState) {
@@ -133,12 +168,48 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>
        }
    }

    private String describeState(@State int stateFlag) {
        switch(stateFlag) {
            case STATE_DOZING:
                return "dozing";
            case STATE_BOUNCER_SHOWING:
                return "bouncer_showing";
            case STATE_KEYGUARD_SHOWING:
                return "keyguard_showing";
            default:
                return "UNDEFINED_STATE";
        }
    }

    private String describeState() {
        StringBuilder stringBuilder = new StringBuilder();

        if ((mState & STATE_KEYGUARD_SHOWING) == STATE_KEYGUARD_SHOWING) {
            stringBuilder.append(String.format(STATE_LIST_FORMAT,
                    describeState(STATE_KEYGUARD_SHOWING)));
        }
        if ((mState & STATE_DOZING) == STATE_DOZING) {
            stringBuilder.append(String.format(STATE_LIST_FORMAT,
                    describeState(STATE_DOZING)));
        }
        if ((mState & STATE_BOUNCER_SHOWING) == STATE_BOUNCER_SHOWING) {
            stringBuilder.append(String.format(STATE_LIST_FORMAT,
                    describeState(STATE_BOUNCER_SHOWING)));
        }

        return stringBuilder.toString();
    }

    private void showSource() {
        // Make sure all necessary states are present for showing communal and all invalid states
        // are absent
        mMainExecutor.execute(() -> {
            final CommunalSource currentSource = mLastSource != null ? mLastSource.get() : null;

            if (DEBUG) {
                Log.d(TAG, "showSource. currentSource:" + currentSource);
            }

            if ((mState & SHOW_COMMUNAL_VIEW_REQUIRED_STATES) == SHOW_COMMUNAL_VIEW_REQUIRED_STATES
                    && (mState & SHOW_COMMUNAL_VIEW_INVALID_STATES) == 0
                    && currentSource != null) {
+60 −5
Original line number Diff line number Diff line
@@ -19,12 +19,13 @@ package com.android.systemui.communal;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.view.View;

import androidx.test.filters.SmallTest;

import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -45,7 +46,7 @@ import java.lang.ref.WeakReference;
@RunWith(AndroidTestingRunner.class)
public class CommunalHostViewControllerTest extends SysuiTestCase {
    @Mock
    private Context mContext;
    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;

    @Mock
    private KeyguardStateController mKeyguardStateController;
@@ -70,10 +71,11 @@ public class CommunalHostViewControllerTest extends SysuiTestCase {
        when(mKeyguardStateController.isShowing()).thenReturn(true);
        when(mCommunalView.isAttachedToWindow()).thenReturn(true);

        mController = new CommunalHostViewController(mFakeExecutor, mKeyguardStateController,
                mStatusBarStateController, mCommunalView);
        mController = new CommunalHostViewController(mFakeExecutor, mKeyguardUpdateMonitor,
                mKeyguardStateController, mStatusBarStateController, mCommunalView);
        mController.init();
        mFakeExecutor.runAllReady();
        Mockito.clearInvocations(mCommunalView);
    }

    @Test
@@ -86,7 +88,6 @@ public class CommunalHostViewControllerTest extends SysuiTestCase {

        // Verify the communal view is shown when the controller is initialized with keyguard
        // showing (see setup).
        Mockito.clearInvocations(mCommunalView);
        mController.show(new WeakReference<>(mCommunalSource));
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.VISIBLE);
@@ -97,4 +98,58 @@ public class CommunalHostViewControllerTest extends SysuiTestCase {
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.INVISIBLE);
    }

    @Test
    public void testHideOnBouncer() {
        ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
                ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);

        // Capture callback value for later use.
        verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());

        // Establish a visible communal view.
        mController.show(new WeakReference<>(mCommunalSource));
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.VISIBLE);
        Mockito.clearInvocations(mCommunalView);

        // Trigger bouncer.
        Mockito.clearInvocations(mCommunalView);
        callbackCapture.getValue().onKeyguardBouncerChanged(true);
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.INVISIBLE);

        // Hide bouncer
        Mockito.clearInvocations(mCommunalView);
        callbackCapture.getValue().onKeyguardBouncerChanged(false);
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.VISIBLE);
    }

    @Test
    public void testHideOnOcclude() {
        ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
                ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);

        // Capture callback value for later use.
        verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());

        // Establish a visible communal view.
        mController.show(new WeakReference<>(mCommunalSource));
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.VISIBLE);
        Mockito.clearInvocations(mCommunalView);

        // Occlude.
        Mockito.clearInvocations(mCommunalView);
        callbackCapture.getValue().onKeyguardOccludedChanged(true);
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.INVISIBLE);

        // Unocclude.
        Mockito.clearInvocations(mCommunalView);
        callbackCapture.getValue().onKeyguardOccludedChanged(false);
        mFakeExecutor.runAllReady();
        verify(mCommunalView).setVisibility(View.VISIBLE);
    }
}