diff options
6 files changed, 103 insertions, 23 deletions
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java index 82571db469be..e9bb28c252e0 100644 --- a/core/java/android/service/dreams/DreamManagerInternal.java +++ b/core/java/android/service/dreams/DreamManagerInternal.java @@ -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() { + } } } diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java index de10b1b19a33..6d70d21e3b84 100644 --- a/services/core/java/com/android/server/dreams/DreamController.java +++ b/services/core/java/com/android/server/dreams/DreamController.java @@ -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); } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 0e26d4661017..d2dcc508d01f 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -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); } }); } @@ -767,12 +782,23 @@ 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) { if (mCurrentDream != null && mCurrentDream.token == token) { cleanupDreamLocked(); } } + + reportDreamingStopped(); } }; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index fc6b4e9dcb20..38c2be83f070 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -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); @@ -4774,21 +4768,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) { diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 646dc4e98c39..495e239d4cd7 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -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() { diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java index 1ef11974292b..d5ad815d3cdb 100644 --- a/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java @@ -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"); @@ -104,6 +113,37 @@ public class DreamControllerTest { } @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. mDreamController.startDream(mToken, mDreamName, true /*isPreview*/, false /*doze*/, |