CommunalStateController Introduction.
This changelist adds the CommunalStateController, which is responsible for reporting the whether the communal view is showing and other state. The communal view state is reported through the CommunalSurfaceViewController when shown and CommunalSurfaceHostViewController when hiding. Bug: 195601027 Test: atest CommunalSurfaceViewControllerTest#testCommunalStateControllerShowNotified Test: atest CommunalHostViewControllerTest#testCommunalStateControllerHideNotified Test: atest CommunalStateControllerTest Change-Id: I2a18a50c8c78e811cd234773994f4591a32303b5
This commit is contained in:
@@ -47,6 +47,7 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>
|
||||
private static final String STATE_LIST_FORMAT = "[%s]";
|
||||
|
||||
private final Executor mMainExecutor;
|
||||
private final CommunalStateController mCommunalStateController;
|
||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final StatusBarStateController mStatusBarStateController;
|
||||
@@ -117,10 +118,12 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>
|
||||
|
||||
@Inject
|
||||
protected CommunalHostViewController(@Main Executor mainExecutor,
|
||||
CommunalStateController communalStateController,
|
||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
KeyguardStateController keyguardStateController,
|
||||
StatusBarStateController statusBarStateController, CommunalHostView view) {
|
||||
super(view);
|
||||
mCommunalStateController = communalStateController;
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mMainExecutor = mainExecutor;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
@@ -247,6 +250,7 @@ public class CommunalHostViewController extends ViewController<CommunalHostView>
|
||||
} else {
|
||||
mView.removeAllViews();
|
||||
mView.setVisibility(View.INVISIBLE);
|
||||
mCommunalStateController.setCommunalViewShowing(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.communal;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.statusbar.policy.CallbackController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* CommunalStateController enables publishing and listening to communal-related state changes.
|
||||
*/
|
||||
@SysUISingleton
|
||||
public class CommunalStateController implements
|
||||
CallbackController<CommunalStateController.Callback> {
|
||||
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
|
||||
private boolean mCommunalViewShowing;
|
||||
|
||||
/**
|
||||
* Callback for communal events.
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when the visibility of the communal view changes.
|
||||
*/
|
||||
default void onCommunalViewShowingChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Inject
|
||||
public CommunalStateController() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the communal view is showing.
|
||||
* @param communalViewShowing {@code true} if the view is showing, {@code false} otherwise.
|
||||
*/
|
||||
public void setCommunalViewShowing(boolean communalViewShowing) {
|
||||
if (mCommunalViewShowing != communalViewShowing) {
|
||||
mCommunalViewShowing = communalViewShowing;
|
||||
|
||||
final ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
|
||||
for (Callback callback : callbacks) {
|
||||
callback.onCommunalViewShowingChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the communal view is showing.
|
||||
* @return {@code true} if the view is showing, {@code false} otherwise.
|
||||
*/
|
||||
public boolean getCommunalViewShowing() {
|
||||
return mCommunalViewShowing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(@NonNull Callback callback) {
|
||||
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
|
||||
if (!mCallbacks.contains(callback)) {
|
||||
mCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallback(@NonNull Callback callback) {
|
||||
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
|
||||
mCallbacks.remove(callback);
|
||||
}
|
||||
}
|
||||
@@ -38,18 +38,21 @@ import javax.inject.Inject;
|
||||
public class CommunalService extends Service {
|
||||
final Executor mMainExecutor;
|
||||
final CommunalSourceMonitor mMonitor;
|
||||
private final CommunalSourceImpl.Factory mSourceFactory;
|
||||
|
||||
private ICommunalHost.Stub mBinder = new ICommunalHost.Stub() {
|
||||
@Override
|
||||
public void setSource(ICommunalSource source) {
|
||||
mMonitor.setSource(
|
||||
source != null ? new CommunalSourceImpl(mMainExecutor, source) : null);
|
||||
source != null ? mSourceFactory.create(source) : null);
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
CommunalService(@Main Executor mainExecutor, CommunalSourceMonitor monitor) {
|
||||
CommunalService(@Main Executor mainExecutor, CommunalSourceImpl.Factory sourceFactory,
|
||||
CommunalSourceMonitor monitor) {
|
||||
mMainExecutor = mainExecutor;
|
||||
mSourceFactory = sourceFactory;
|
||||
mMonitor = monitor;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.view.SurfaceView;
|
||||
import androidx.concurrent.futures.CallbackToFutureAdapter;
|
||||
|
||||
import com.android.systemui.communal.CommunalSource;
|
||||
import com.android.systemui.communal.CommunalStateController;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.shared.communal.ICommunalSource;
|
||||
import com.android.systemui.shared.communal.ICommunalSurfaceCallback;
|
||||
@@ -49,17 +50,20 @@ public class CommunalSourceImpl implements CommunalSource {
|
||||
private static final boolean DEBUG = false;
|
||||
private final ICommunalSource mSourceProxy;
|
||||
private final Executor mMainExecutor;
|
||||
private final CommunalStateController mCommunalStateController;
|
||||
|
||||
static class Factory {
|
||||
private final Executor mExecutor;
|
||||
private final CommunalStateController mCommunalStateController;
|
||||
|
||||
@Inject
|
||||
Factory(@Main Executor executor) {
|
||||
Factory(@Main Executor executor, CommunalStateController communalStateController) {
|
||||
mExecutor = executor;
|
||||
mCommunalStateController = communalStateController;
|
||||
}
|
||||
|
||||
public CommunalSource create(ICommunalSource source) {
|
||||
return new CommunalSourceImpl(mExecutor, source);
|
||||
return new CommunalSourceImpl(mExecutor, mCommunalStateController, source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +75,10 @@ public class CommunalSourceImpl implements CommunalSource {
|
||||
// A list of {@link Callback} that have registered to receive updates.
|
||||
private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
|
||||
|
||||
public CommunalSourceImpl(Executor mainExecutor, ICommunalSource sourceProxy) {
|
||||
public CommunalSourceImpl(Executor mainExecutor,
|
||||
CommunalStateController communalStateController, ICommunalSource sourceProxy) {
|
||||
mMainExecutor = mainExecutor;
|
||||
mCommunalStateController = communalStateController;
|
||||
mSourceProxy = sourceProxy;
|
||||
|
||||
try {
|
||||
@@ -114,7 +120,8 @@ public class CommunalSourceImpl implements CommunalSource {
|
||||
CallbackToFutureAdapter.getFuture(completer -> {
|
||||
final SurfaceView view = new SurfaceView(context);
|
||||
completer.set(new CommunalViewResult(view,
|
||||
new CommunalSurfaceViewController(view, mMainExecutor, this)));
|
||||
new CommunalSurfaceViewController(view, mMainExecutor,
|
||||
mCommunalStateController, this)));
|
||||
return "CommunalSourceImpl::requestCommunalSurface::getCommunalSurface";
|
||||
});
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.view.SurfaceView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.systemui.communal.CommunalStateController;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
@@ -38,6 +39,7 @@ public class CommunalSurfaceViewController extends ViewController<SurfaceView> {
|
||||
private static final String TAG = "CommunalSurfaceViewCtlr";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private final Executor mMainExecutor;
|
||||
private final CommunalStateController mCommunalStateController;
|
||||
private final CommunalSourceImpl mSource;
|
||||
|
||||
@IntDef({STATE_SURFACE_CREATED, STATE_SURFACE_VIEW_ATTACHED})
|
||||
@@ -72,8 +74,9 @@ public class CommunalSurfaceViewController extends ViewController<SurfaceView> {
|
||||
};
|
||||
|
||||
protected CommunalSurfaceViewController(SurfaceView view, Executor executor,
|
||||
CommunalSourceImpl source) {
|
||||
CommunalStateController communalStateController, CommunalSourceImpl source) {
|
||||
super(view);
|
||||
mCommunalStateController = communalStateController;
|
||||
mSource = source;
|
||||
mMainExecutor = executor;
|
||||
}
|
||||
@@ -146,6 +149,7 @@ public class CommunalSurfaceViewController extends ViewController<SurfaceView> {
|
||||
mView.setChildSurfacePackage(surfacePackage);
|
||||
mView.setZOrderOnTop(true);
|
||||
mView.postInvalidate();
|
||||
mCommunalStateController.setCommunalViewShowing(true);
|
||||
} else {
|
||||
Log.e(TAG, "couldn't get the surface package");
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.communal;
|
||||
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -45,6 +46,9 @@ import java.lang.ref.WeakReference;
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class CommunalHostViewControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private CommunalStateController mCommunalStateController;
|
||||
|
||||
@Mock
|
||||
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
|
||||
@@ -71,8 +75,9 @@ public class CommunalHostViewControllerTest extends SysuiTestCase {
|
||||
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
||||
when(mCommunalView.isAttachedToWindow()).thenReturn(true);
|
||||
|
||||
mController = new CommunalHostViewController(mFakeExecutor, mKeyguardUpdateMonitor,
|
||||
mKeyguardStateController, mStatusBarStateController, mCommunalView);
|
||||
mController = new CommunalHostViewController(mFakeExecutor, mCommunalStateController,
|
||||
mKeyguardUpdateMonitor, mKeyguardStateController, mStatusBarStateController,
|
||||
mCommunalView);
|
||||
mController.init();
|
||||
mFakeExecutor.runAllReady();
|
||||
Mockito.clearInvocations(mCommunalView);
|
||||
@@ -152,4 +157,25 @@ public class CommunalHostViewControllerTest extends SysuiTestCase {
|
||||
mFakeExecutor.runAllReady();
|
||||
verify(mCommunalView).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunalStateControllerHideNotified() {
|
||||
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();
|
||||
|
||||
// Occlude
|
||||
clearInvocations(mCommunalStateController);
|
||||
callbackCapture.getValue().onKeyguardOccludedChanged(true);
|
||||
mFakeExecutor.runAllReady();
|
||||
|
||||
// Verify state controller is notified communal view is hidden.
|
||||
verify(mCommunalStateController).setCommunalViewShowing(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.communal;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class CommunalStateControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private CommunalStateController.Callback mCallback;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultCommunalViewShowingState() {
|
||||
// The state controller should report the communal view as not showing by default.
|
||||
final CommunalStateController stateController = new CommunalStateController();
|
||||
assertThat(stateController.getCommunalViewShowing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifyCommunalSurfaceShow() {
|
||||
final CommunalStateController stateController = new CommunalStateController();
|
||||
stateController.addCallback(mCallback);
|
||||
|
||||
// Verify setting communal view to showing propagates to callback.
|
||||
stateController.setCommunalViewShowing(true);
|
||||
verify(mCallback).onCommunalViewShowingChanged();
|
||||
assertThat(stateController.getCommunalViewShowing()).isTrue();
|
||||
|
||||
clearInvocations(mCallback);
|
||||
|
||||
// Verify setting communal view to not showing propagates to callback.
|
||||
stateController.setCommunalViewShowing(false);
|
||||
verify(mCallback).onCommunalViewShowingChanged();
|
||||
assertThat(stateController.getCommunalViewShowing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallbackRegistration() {
|
||||
final CommunalStateController stateController = new CommunalStateController();
|
||||
stateController.addCallback(mCallback);
|
||||
|
||||
// Verify setting communal view to showing propagates to callback.
|
||||
stateController.setCommunalViewShowing(true);
|
||||
verify(mCallback).onCommunalViewShowingChanged();
|
||||
|
||||
clearInvocations(mCallback);
|
||||
|
||||
stateController.removeCallback(mCallback);
|
||||
clearInvocations(mCallback);
|
||||
|
||||
// Verify callback not invoked after removing from state controller.
|
||||
stateController.setCommunalViewShowing(false);
|
||||
verify(mCallback, never()).onCommunalViewShowingChanged();
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import android.view.SurfaceView;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.communal.CommunalStateController;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
@@ -68,6 +69,9 @@ public class CommunalSurfaceViewControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
|
||||
|
||||
@Mock
|
||||
private CommunalStateController mCommunalStateController;
|
||||
|
||||
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
|
||||
|
||||
private SurfaceHolder.Callback mCallback;
|
||||
@@ -89,7 +93,7 @@ public class CommunalSurfaceViewControllerTest extends SysuiTestCase {
|
||||
when(mSurfaceView.getMeasuredHeight()).thenReturn(MEASURED_HEIGHT);
|
||||
when(mSurfaceView.isAttachedToWindow()).thenReturn(false);
|
||||
mController = new CommunalSurfaceViewController(mSurfaceView, mFakeExecutor,
|
||||
mCommunalSource);
|
||||
mCommunalStateController, mCommunalSource);
|
||||
mController.init();
|
||||
verify(mSurfaceHolder).addCallback(callbackCapture.capture());
|
||||
mCallback = callbackCapture.getValue();
|
||||
@@ -131,6 +135,19 @@ public class CommunalSurfaceViewControllerTest extends SysuiTestCase {
|
||||
verify(mSurfaceView).setWillNotDraw(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommunalStateControllerShowNotified() {
|
||||
// Move CommunalSurfaceView to show
|
||||
mController.onViewAttached();
|
||||
mCallback.surfaceCreated(mSurfaceHolder);
|
||||
when(mSurfaceView.isAttachedToWindow()).thenReturn(true);
|
||||
mPackageFuture.set(mSurfacePackage);
|
||||
mFakeExecutor.runAllReady();
|
||||
|
||||
// Ensure state controller is informed that the communal view is showing.
|
||||
verify(mCommunalStateController).setCommunalViewShowing(true);
|
||||
}
|
||||
|
||||
// Invoked to setup surface view package.
|
||||
private void givenSurfacePresent() {
|
||||
mController.onViewAttached();
|
||||
|
||||
Reference in New Issue
Block a user