Merge "CommunalStateController Introduction."
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