summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Bryce Lee <brycelee@google.com> 2021-09-30 15:57:26 -0700
committer Bryce Lee <brycelee@google.com> 2021-10-27 08:39:20 -0700
commit87a5024ef5ed68f36b2c6618b13fa4512e06c47c (patch)
treefac9abe9bc8a0493df82639cab871143f9b9f1fd
parent22f575a03657110b736705daecb5bc4cdefb1a13 (diff)
IDreamOverlay Introduction.
This changelist introduces IDreamOverlay, an interface for rendering an overlay on top of a Dream. IDreamOverlay implementations can register with DreamManagerService to be bound to by DreamService when dream commences. The overlay will be passed the Dream Window information so that it may render within this window space. Bug: 201676854 Test: atest DreamOverlayTest Change-Id: I382ba2acb4a6922f19250753f8f0afc4181a6454
-rw-r--r--core/java/android/service/dreams/DreamService.java94
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl1
-rw-r--r--core/java/android/service/dreams/IDreamOverlay.aidl37
-rw-r--r--core/java/android/service/dreams/IDreamOverlayCallback.aidl31
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java4
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java14
6 files changed, 179 insertions, 2 deletions
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 98196489a2ed..096595f30b05 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -26,7 +26,10 @@ import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -58,6 +61,8 @@ import com.android.internal.util.DumpUtils.Dump;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
+import java.util.function.Consumer;
/**
* Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -170,6 +175,13 @@ public class DreamService extends Service implements Window.Callback {
"android.service.dreams.DreamService";
/**
+ * The name of the extra where the dream overlay component is stored.
+ * @hide
+ */
+ public static final String EXTRA_DREAM_OVERLAY_COMPONENT =
+ "android.service.dream.DreamService.dream_overlay_component";
+
+ /**
* Name under which a Dream publishes information about itself.
* This meta-data must reference an XML resource containing
* a <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code>
@@ -191,6 +203,7 @@ public class DreamService extends Service implements Window.Callback {
private boolean mCanDoze;
private boolean mDozing;
private boolean mWindowless;
+ private boolean mOverlayServiceBound;
private int mDozeScreenState = Display.STATE_UNKNOWN;
private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
@@ -199,8 +212,62 @@ public class DreamService extends Service implements Window.Callback {
private DreamServiceWrapper mDreamServiceWrapper;
private Runnable mDispatchAfterOnAttachedToWindow;
+ private OverlayConnection mOverlayConnection;
+
+ private static class OverlayConnection implements ServiceConnection {
+ // Overlay set during onBind.
+ private IDreamOverlay mOverlay;
+ // A Queue of pending requests to execute on the overlay.
+ private ArrayDeque<Consumer<IDreamOverlay>> mRequests;
+
+ OverlayConnection() {
+ mRequests = new ArrayDeque<>();
+ }
+
+ public void request(Consumer<IDreamOverlay> request) {
+ mRequests.push(request);
+ evaluate();
+ }
+
+ private void evaluate() {
+ if (mOverlay == null) {
+ return;
+ }
+
+ // Any new requests that arrive during this loop will be processed synchronously after
+ // the loop exits.
+ while (!mRequests.isEmpty()) {
+ final Consumer<IDreamOverlay> request = mRequests.pop();
+ request.accept(mOverlay);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ // Store Overlay and execute pending requests.
+ mOverlay = IDreamOverlay.Stub.asInterface(service);
+ evaluate();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Clear Overlay binder to prevent further request processing.
+ mOverlay = null;
+ }
+ }
+
+ private IDreamOverlayCallback mOverlayCallback = new IDreamOverlayCallback.Stub() {
+ @Override
+ public void onExitRequested() {
+ // Simply finish dream when exit is requested.
+ finish();
+ }
+ };
+
+
public DreamService() {
mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
+ mOverlayConnection = new OverlayConnection();
}
/**
@@ -861,6 +928,18 @@ public class DreamService extends Service implements Window.Callback {
public final IBinder onBind(Intent intent) {
if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
mDreamServiceWrapper = new DreamServiceWrapper();
+
+ // Connect to the overlay service if present.
+ final ComponentName overlayComponent =
+ intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT);
+ if (overlayComponent != null && !mWindowless) {
+ final Intent overlayIntent = new Intent();
+ overlayIntent.setComponent(overlayComponent);
+
+ mOverlayServiceBound = getApplicationContext().bindService(overlayIntent,
+ mOverlayConnection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
+ }
+
return mDreamServiceWrapper;
}
@@ -894,6 +973,11 @@ public class DreamService extends Service implements Window.Callback {
return;
}
+ if (!mWindowless && mOverlayServiceBound) {
+ unbindService(mOverlayConnection);
+ mOverlayServiceBound = false;
+ }
+
try {
// finishSelf will unbind the dream controller from the dream service. This will
// trigger DreamService.this.onDestroy and DreamService.this will die.
@@ -1101,6 +1185,16 @@ public class DreamService extends Service implements Window.Callback {
}
}
});
+
+ // Request the DreamOverlay be told to dream with dream's window parameters once the service
+ // has connected.
+ mOverlayConnection.request(overlay -> {
+ try {
+ overlay.startDream(mWindow.getAttributes(), mOverlayCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "could not send window attributes:" + e);
+ }
+ });
}
private boolean getWindowFlagValue(int flag, boolean defaultValue) {
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 0ce9cfa7a0bf..3e0deeb556e9 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -41,4 +41,5 @@ interface IDreamManager {
void forceAmbientDisplayEnabled(boolean enabled);
ComponentName[] getDreamComponentsForUser(int userId);
void setDreamComponentsForUser(int userId, in ComponentName[] componentNames);
+ void registerDreamOverlayService(in ComponentName componentName);
}
diff --git a/core/java/android/service/dreams/IDreamOverlay.aidl b/core/java/android/service/dreams/IDreamOverlay.aidl
new file mode 100644
index 000000000000..2b6633d93dc5
--- /dev/null
+++ b/core/java/android/service/dreams/IDreamOverlay.aidl
@@ -0,0 +1,37 @@
+/**
+ * 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 android.service.dreams;
+
+import android.service.dreams.IDreamOverlayCallback;
+import android.view.WindowManager.LayoutParams;
+
+/**
+* {@link IDreamOverlay} provides a way for a component to annotate a dream with additional view
+* elements. Registered through the DreamManager, a IDreamOverlay is bound to by the dream and
+* passed the necessary window details to participate in the user interface.
+
+* @hide
+*/
+interface IDreamOverlay {
+ /**
+ * @param params The {@link LayoutParams} for the associated DreamWindow, including the window
+ token of the Dream Activity.
+ * @param callback The {@link IDreamOverlayCallback} for requesting actions such as exiting the
+ * dream.
+ */
+ void startDream(in LayoutParams params, in IDreamOverlayCallback callback);
+}
diff --git a/core/java/android/service/dreams/IDreamOverlayCallback.aidl b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
new file mode 100644
index 000000000000..ec76a334d5b2
--- /dev/null
+++ b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
@@ -0,0 +1,31 @@
+/**
+ * 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 android.service.dreams;
+
+/**
+* {@link IDreamOverlayCallback} defines the interactions a dream overlay can have with its
+* associated dream. It is the discretion of the {@link DreamService}) to honor any inbound requests
+* from this callback.
+*
+* @hide
+*/
+interface IDreamOverlayCallback {
+ /**
+ * Invoked to request the dream exit.
+ */
+ void onExitRequested();
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 5bc69943033e..76754d3e95d5 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -117,7 +117,8 @@ final class DreamController {
}
public void startDream(Binder token, ComponentName name,
- boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
+ boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
+ ComponentName overlayComponentName) {
stopDream(true /*immediate*/, "starting new dream");
Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
@@ -138,6 +139,7 @@ final class DreamController {
Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(DreamService.EXTRA_DREAM_OVERLAY_COMPONENT, overlayComponentName);
try {
if (!mContext.bindServiceAsUser(intent, mCurrentDream,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 3a7220f7592f..258689a3ed93 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -95,6 +95,8 @@ public final class DreamManagerService extends SystemService {
private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ private ComponentName mDreamOverlayServiceName;
+
private AmbientDisplayConfiguration mDozeConfig;
@VisibleForTesting
@@ -421,7 +423,8 @@ public final class DreamManagerService extends SystemService {
if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
mUiEventLogger.log(DreamManagerEvent.DREAM_START);
}
- mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock);
+ mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock,
+ mDreamOverlayServiceName);
}));
}
@@ -592,6 +595,15 @@ public final class DreamManagerService extends SystemService {
}
@Override // Binder call
+ public void registerDreamOverlayService(ComponentName overlayComponent) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ // Store the overlay service component so that it can be passed to the dream when it is
+ // invoked.
+ mDreamOverlayServiceName = overlayComponent;
+ }
+
+ @Override // Binder call
public ComponentName getDefaultDreamComponentForUser(int userId) {
checkPermission(android.Manifest.permission.READ_DREAM_STATE);
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),