summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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(),