Merge changes Idd362f88,Ifb1e1266 into udc-dev

* changes:
  Use KeyguardUpdateMonitor in DreamCondition.
  Send dream state updates through DreamManagerStateListener.
This commit is contained in:
Bryce Lee
2023-04-21 14:54:16 +00:00
committed by Android (Google) Code Review
8 changed files with 137 additions and 67 deletions

View File

@@ -84,6 +84,19 @@ public abstract class DreamManagerInternal {
*
* @param keepDreaming True if the current dream should continue when undocking.
*/
void onKeepDreamingWhenUnpluggingChanged(boolean keepDreaming);
default void onKeepDreamingWhenUnpluggingChanged(boolean keepDreaming) {
}
/**
* Called when dreaming has started.
*/
default void onDreamingStarted() {
}
/**
* Called when dreaming has stopped.
*/
default void onDreamingStopped() {
}
}
}

View File

@@ -16,12 +16,9 @@
package com.android.systemui.dreams.conditions;
import android.app.DreamManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.text.TextUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.shared.condition.Condition;
import javax.inject.Inject;
@@ -30,48 +27,33 @@ import javax.inject.Inject;
* {@link DreamCondition} provides a signal when a dream begins and ends.
*/
public class DreamCondition extends Condition {
private final Context mContext;
private final DreamManager mDreamManager;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
processIntent(intent);
}
};
private final KeyguardUpdateMonitor mUpdateMonitor;
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onDreamingStateChanged(boolean dreaming) {
updateCondition(dreaming);
}
};
@Inject
public DreamCondition(Context context,
DreamManager dreamManager) {
mContext = context;
public DreamCondition(DreamManager dreamManager, KeyguardUpdateMonitor monitor) {
mDreamManager = dreamManager;
}
private void processIntent(Intent intent) {
// In the case of a non-existent sticky broadcast, ignore when there is no intent.
if (intent == null) {
return;
}
if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STARTED)) {
updateCondition(true);
} else if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STOPPED)) {
updateCondition(false);
} else {
throw new IllegalStateException("unexpected intent:" + intent);
}
mUpdateMonitor = monitor;
}
@Override
protected void start() {
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiver(mReceiver, filter);
mUpdateMonitor.registerCallback(mUpdateCallback);
updateCondition(mDreamManager.isDreaming());
}
@Override
protected void stop() {
mContext.unregisterReceiver(mReceiver);
mUpdateMonitor.removeCallback(mUpdateCallback);
}
}

View File

@@ -18,7 +18,6 @@ package com.android.systemui.dreams.conditions;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
@@ -26,13 +25,13 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.DreamManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.shared.condition.Condition;
@@ -55,6 +54,9 @@ public class DreamConditionTest extends SysuiTestCase {
@Mock
DreamManager mDreamManager;
@Mock
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -66,7 +68,7 @@ public class DreamConditionTest extends SysuiTestCase {
@Test
public void testInitialDreamingState() {
when(mDreamManager.isDreaming()).thenReturn(true);
final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mCallback).onConditionChanged(eq(condition));
@@ -79,7 +81,7 @@ public class DreamConditionTest extends SysuiTestCase {
@Test
public void testInitialNonDreamingState() {
when(mDreamManager.isDreaming()).thenReturn(false);
final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mCallback, never()).onConditionChanged(eq(condition));
@@ -91,15 +93,21 @@ public class DreamConditionTest extends SysuiTestCase {
*/
@Test
public void testChange() {
final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
final ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCaptor =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
when(mDreamManager.isDreaming()).thenReturn(true);
final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mContext).registerReceiver(receiverCaptor.capture(), any());
verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture());
clearInvocations(mCallback);
receiverCaptor.getValue().onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
callbackCaptor.getValue().onDreamingStateChanged(false);
verify(mCallback).onConditionChanged(eq(condition));
assertThat(condition.isConditionMet()).isFalse();
clearInvocations(mCallback);
callbackCaptor.getValue().onDreamingStateChanged(true);
verify(mCallback).onConditionChanged(eq(condition));
assertThat(condition.isConditionMet()).isTrue();
}
}

View File

@@ -345,6 +345,7 @@ final class DreamController {
if (!mCurrentDream.mIsPreviewMode && !mSentStartBroadcast) {
mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL,
null /* receiverPermission */, mDreamingStartedStoppedOptions);
mListener.onDreamStarted(mCurrentDream.mToken);
mSentStartBroadcast = true;
}
}
@@ -353,6 +354,7 @@ final class DreamController {
* Callback interface to be implemented by the {@link DreamManagerService}.
*/
public interface Listener {
void onDreamStarted(Binder token);
void onDreamStopped(Binder token);
}

View File

@@ -84,6 +84,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
/**
* Service api for managing dreams.
@@ -341,10 +342,24 @@ public final class DreamManagerService extends SystemService {
}
private void reportKeepDreamingWhenUnpluggingChanged(boolean keepDreaming) {
notifyDreamStateListeners(
listener -> listener.onKeepDreamingWhenUnpluggingChanged(keepDreaming));
}
private void reportDreamingStarted() {
notifyDreamStateListeners(listener -> listener.onDreamingStarted());
}
private void reportDreamingStopped() {
notifyDreamStateListeners(listener -> listener.onDreamingStopped());
}
private void notifyDreamStateListeners(
Consumer<DreamManagerInternal.DreamManagerStateListener> notifier) {
mHandler.post(() -> {
for (DreamManagerInternal.DreamManagerStateListener listener
: mDreamManagerStateListeners) {
listener.onKeepDreamingWhenUnpluggingChanged(keepDreaming);
notifier.accept(listener);
}
});
}
@@ -766,6 +781,15 @@ public final class DreamManagerService extends SystemService {
}
private final DreamController.Listener mControllerListener = new DreamController.Listener() {
@Override
public void onDreamStarted(Binder token) {
// Note that this event is distinct from DreamManagerService#startDreamLocked as it
// tracks the DreamService attach point from DreamController, closest to the broadcast
// of ACTION_DREAMING_STARTED.
reportDreamingStarted();
}
@Override
public void onDreamStopped(Binder token) {
synchronized (mLock) {
@@ -773,6 +797,8 @@ public final class DreamManagerService extends SystemService {
cleanupDreamLocked();
}
}
reportDreamingStopped();
}
};

View File

@@ -2186,12 +2186,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Intent.EXTRA_DOCK_STATE_UNDOCKED));
}
// register for dream-related broadcasts
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiver(mDreamReceiver, filter);
// register for multiuser-relevant broadcasts
filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mMultiuserReceiver, filter);
@@ -4785,21 +4779,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
};
BroadcastReceiver mDreamReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onDreamingStarted();
}
} else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onDreamingStopped();
}
}
}
};
BroadcastReceiver mMultiuserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

View File

@@ -18,6 +18,7 @@ import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.dreams.DreamManagerInternal;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -27,6 +28,7 @@ import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy.OnKeyguardExitResult;
import com.android.server.wm.EventLogTags;
@@ -60,6 +62,19 @@ public class KeyguardServiceDelegate {
private DrawnListener mDrawnListenerWhenConnect;
private final DreamManagerInternal.DreamManagerStateListener mDreamManagerStateListener =
new DreamManagerInternal.DreamManagerStateListener() {
@Override
public void onDreamingStarted() {
KeyguardServiceDelegate.this.onDreamingStarted();
}
@Override
public void onDreamingStopped() {
KeyguardServiceDelegate.this.onDreamingStopped();
}
};
private static final class KeyguardState {
KeyguardState() {
reset();
@@ -158,6 +173,11 @@ public class KeyguardServiceDelegate {
} else {
if (DEBUG) Log.v(TAG, "*** Keyguard started");
}
final DreamManagerInternal dreamManager =
LocalServices.getService(DreamManagerInternal.class);
dreamManager.registerDreamManagerStateListener(mDreamManagerStateListener);
}
private final ServiceConnection mKeyguardConnection = new ServiceConnection() {

View File

@@ -25,6 +25,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
@@ -54,6 +55,10 @@ public class DreamControllerTest {
private DreamController.Listener mListener;
@Mock
private Context mContext;
@Mock
private ActivityTaskManager mActivityTaskManager;
@Mock
private IBinder mIBinder;
@Mock
@@ -80,6 +85,10 @@ public class DreamControllerTest {
when(mIDreamService.asBinder()).thenReturn(mIBinder);
when(mIBinder.queryLocalInterface(anyString())).thenReturn(mIDreamService);
when(mContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
when(mContext.getSystemService(Context.ACTIVITY_TASK_SERVICE))
.thenReturn(mActivityTaskManager);
when(mContext.getSystemServiceName(ActivityTaskManager.class))
.thenReturn(Context.ACTIVITY_TASK_SERVICE);
mToken = new Binder();
mDreamName = ComponentName.unflattenFromString("dream");
@@ -103,6 +112,37 @@ public class DreamControllerTest {
eq(false) /*preview*/, any());
}
@Test
public void startDream_dreamListenerNotified() {
// Call dream controller to start dreaming.
mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
// Mock service connected.
final ServiceConnection serviceConnection = captureServiceConnection();
serviceConnection.onServiceConnected(mDreamName, mIBinder);
mLooper.dispatchAll();
// Verify that dream service is called to attach.
verify(mListener).onDreamStarted(any());
}
@Test
public void stopDream_dreamListenerNotified() {
// Start dream.
mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
captureServiceConnection().onServiceConnected(mDreamName, mIBinder);
mLooper.dispatchAll();
// Stop dream.
mDreamController.stopDream(true /*immediate*/, "test stop dream" /*reason*/);
mLooper.dispatchAll();
// Verify that dream service is called to detach.
verify(mListener).onDreamStopped(any());
}
@Test
public void startDream_attachOnServiceConnectedInPreviewMode() throws RemoteException {
// Call dream controller to start dreaming.