Merge changes Id71b4cbc,I8dff0a12,Ife3d1390 into rvc-dev
* changes:
Add startDreamActivity request verification
Make DreamService use an Activity
Clean up dreamland
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 4e3aa7d..266a06a 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -98,6 +98,14 @@
in ProfilerInfo profilerInfo, in Bundle options, int userId);
boolean startNextMatchingActivity(in IBinder callingActivity,
in Intent intent, in Bundle options);
+
+ /**
+ * The DreamActivity has to be started in a special way that does not involve the PackageParser.
+ * The DreamActivity is a framework component inserted in the dream application process. Hence,
+ * it is not declared in the application's manifest and cannot be parsed. startDreamActivity
+ * creates the activity and starts it without reaching out to the PackageParser.
+ */
+ boolean startDreamActivity(in Intent intent);
int startActivityIntentSender(in IApplicationThread caller,
in IIntentSender target, in IBinder whitelistToken, in Intent fillInIntent,
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
new file mode 100644
index 0000000..8cdd24e
--- /dev/null
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 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.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * The Activity used by the {@link DreamService} to draw screensaver content
+ * on the screen. This activity runs in dream application's process, but is started by a
+ * specialized method: {@link com.android.server.wm.ActivityTaskManagerService#startDreamActivity}.
+ * Hence, it does not have to be declared in the dream application's manifest.
+ *
+ * We use an activity as the dream canvas, because it interacts easier with other activities on
+ * the screen (compared to a hover window). However, the DreamService is in charge of the dream and
+ * it receives all Window.Callbacks from its main window. Since a window can have only one callback
+ * receiver, the activity will not receive any window callbacks.
+ *
+ * Prior to the DreamActivity, the DreamService used to work with a hovering window and give the
+ * screensaver application control over that window. The DreamActivity is a replacement to that
+ * hover window. Using an activity allows for better-defined interactions with the rest of the
+ * activities on screen. The switch to DreamActivity should be transparent to the screensaver
+ * application, i.e. the application will still use DreamService APIs and not notice that the
+ * system is using an activity behind the scenes.
+ *
+ * @hide
+ */
+public class DreamActivity extends Activity {
+ static final String EXTRA_CALLBACK = "binder";
+
+ public DreamActivity() {}
+
+ @Override
+ public void onCreate(@Nullable Bundle bundle) {
+ super.onCreate(bundle);
+
+ DreamService.DreamServiceWrapper callback =
+ (DreamService.DreamServiceWrapper) getIntent().getIBinderExtra(EXTRA_CALLBACK);
+
+ if (callback != null) {
+ callback.onActivityCreated(this);
+ }
+ }
+}
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index ff7cef9..41fdd0b 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -16,6 +16,8 @@
package android.service.dreams;
+import android.content.ComponentName;
+
/**
* Dream manager local system service interface.
*
@@ -42,4 +44,13 @@
* Called by the power manager to determine whether a dream is running.
*/
public abstract boolean isDreaming();
+
+ /**
+ * Called by the ActivityTaskManagerService to verify that the startDreamActivity
+ * request comes from the current active dream component.
+ *
+ * @param doze If true returns the current active doze component. Otherwise, returns the
+ * active dream component.
+ */
+ public abstract ComponentName getActiveDreamComponent(boolean doze);
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index de4a551..28f4929 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -15,25 +15,29 @@
*/
package android.service.dreams;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
+import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
import android.view.ActionMode;
@@ -48,10 +52,8 @@
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.policy.PhoneWindow;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils.Dump;
@@ -176,10 +178,11 @@
*/
public static final String DREAM_META_DATA = "android.service.dream";
- private final IDreamManager mSandman;
- private final Handler mHandler = new Handler();
- private IBinder mWindowToken;
+ private final IDreamManager mDreamManager;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private IBinder mDreamToken;
private Window mWindow;
+ private Activity mActivity;
private boolean mInteractive;
private boolean mLowProfile = true;
private boolean mFullscreen;
@@ -195,8 +198,11 @@
private boolean mDebug = false;
+ private DreamServiceWrapper mDreamServiceWrapper;
+ private Runnable mDispatchAfterOnAttachedToWindow;
+
public DreamService() {
- mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
+ mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
}
/**
@@ -602,6 +608,8 @@
* Marks this dream as windowless. Only available to doze dreams.
*
* @hide
+ *
+ * TODO: Remove @UnsupportedAppUsage.
*/
@UnsupportedAppUsage
public void setWindowless(boolean windowless) {
@@ -670,14 +678,14 @@
}
private void updateDoze() {
- if (mWindowToken == null) {
- Slog.w(TAG, "Updating doze without a window token.");
+ if (mDreamToken == null) {
+ Slog.w(TAG, "Updating doze without a dream token.");
return;
}
if (mDozing) {
try {
- mSandman.startDozing(mWindowToken, mDozeScreenState, mDozeScreenBrightness);
+ mDreamManager.startDozing(mDreamToken, mDozeScreenState, mDozeScreenBrightness);
} catch (RemoteException ex) {
// system server died
}
@@ -700,7 +708,7 @@
if (mDozing) {
mDozing = false;
try {
- mSandman.stopDozing(mWindowToken);
+ mDreamManager.stopDozing(mDreamToken);
} catch (RemoteException ex) {
// system server died
}
@@ -875,14 +883,15 @@
* </p>
*/
public void onWakeUp() {
- finish();
+ mActivity.finishAndRemoveTask();
}
/** {@inheritDoc} */
@Override
public final IBinder onBind(Intent intent) {
if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
- return new DreamServiceWrapper();
+ mDreamServiceWrapper = new DreamServiceWrapper();
+ return mDreamServiceWrapper;
}
/**
@@ -895,20 +904,25 @@
public final void finish() {
if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished);
+ if (mActivity == null) {
+ Slog.w(TAG, "Finish was called before the dream was attached.");
+ } else if (!mActivity.isFinishing()) {
+ // In case the activity is not finished yet, do it now. This can happen if someone calls
+ // finish() directly, without going through wakeUp().
+ mActivity.finishAndRemoveTask();
+ return;
+ }
+
if (!mFinished) {
mFinished = true;
- if (mWindowToken == null) {
- Slog.w(TAG, "Finish was called before the dream was attached.");
- } else {
- try {
- mSandman.finishSelf(mWindowToken, true /*immediate*/);
- } catch (RemoteException ex) {
- // system server died
- }
+ try {
+ // finishSelf will unbind the dream controller from the dream service. This will
+ // trigger DreamService.this.onDestroy and DreamService.this will die.
+ mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
+ } catch (RemoteException ex) {
+ // system server died
}
-
- stopSelf(); // if launched via any other means
}
}
@@ -938,11 +952,11 @@
// Now tell the system we are waking gently, unless we already told
// it we were finishing immediately.
if (!fromSystem && !mFinished) {
- if (mWindowToken == null) {
+ if (mActivity == null) {
Slog.w(TAG, "WakeUp was called before the dream was attached.");
} else {
try {
- mSandman.finishSelf(mWindowToken, false /*immediate*/);
+ mDreamManager.finishSelf(mDreamToken, false /*immediate*/);
} catch (RemoteException ex) {
// system server died
}
@@ -977,20 +991,14 @@
onDreamingStopped();
}
- if (mWindow != null) {
- // force our window to be removed synchronously
- if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
- mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
- mWindow = null;
+ if (mActivity != null && !mActivity.isFinishing()) {
+ mActivity.finishAndRemoveTask();
+ } else {
+ finish();
}
- if (mWindowToken != null) {
- // the following will print a log message if it finds any other leaked windows
- WindowManagerGlobal.getInstance().closeAll(mWindowToken,
- this.getClass().getName(), "Dream");
- mWindowToken = null;
- mCanDoze = false;
- }
+ mDreamToken = null;
+ mCanDoze = false;
}
/**
@@ -998,95 +1006,107 @@
*
* Must run on mHandler.
*
- * @param windowToken A window token that will allow a window to be created in the correct layer.
+ * @param dreamToken Token for this dream service.
* @param started A callback that will be invoked once onDreamingStarted has completed.
*/
- private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) {
- if (mWindowToken != null) {
- Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
+ private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) {
+ if (mActivity != null) {
+ Slog.e(TAG, "attach() called when dream with token=" + mDreamToken
+ + " already attached");
return;
}
if (mFinished || mWaking) {
Slog.w(TAG, "attach() called after dream already finished");
try {
- mSandman.finishSelf(windowToken, true /*immediate*/);
+ mDreamManager.finishSelf(dreamToken, true /*immediate*/);
} catch (RemoteException ex) {
// system server died
}
return;
}
- mWindowToken = windowToken;
+ mDreamToken = dreamToken;
mCanDoze = canDoze;
if (mWindowless && !mCanDoze) {
throw new IllegalStateException("Only doze dreams can be windowless");
}
- if (!mWindowless) {
- mWindow = new PhoneWindow(this);
- mWindow.setCallback(this);
- mWindow.requestFeature(Window.FEATURE_NO_TITLE);
- mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
- mWindow.setFormat(PixelFormat.OPAQUE);
- if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
- windowToken, WindowManager.LayoutParams.TYPE_DREAM));
-
- WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.type = WindowManager.LayoutParams.TYPE_DREAM;
- lp.token = windowToken;
- lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
- lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
- | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
- | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
- | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
- );
- mWindow.setAttributes(lp);
- // Workaround: Currently low-profile and in-window system bar backgrounds don't go
- // along well. Dreams usually don't need such bars anyways, so disable them by default.
- mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- mWindow.setWindowManager(null, windowToken, "dream", true);
-
- applySystemUiVisibilityFlags(
- (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
- View.SYSTEM_UI_FLAG_LOW_PROFILE);
-
- try {
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
- } catch (WindowManager.BadTokenException ex) {
- // This can happen because the dream manager service will remove the token
- // immediately without necessarily waiting for the dream to start.
- // We should receive a finish message soon.
- Slog.i(TAG, "attach() called after window token already removed, dream will "
- + "finish soon");
- mWindow = null;
- return;
- }
- }
- // We need to defer calling onDreamingStarted until after onWindowAttached,
- // which is posted to the handler by addView, so we post onDreamingStarted
- // to the handler also. Need to watch out here in case detach occurs before
- // this callback is invoked.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mWindow != null || mWindowless) {
- if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
- mStarted = true;
+ mDispatchAfterOnAttachedToWindow = () -> {
+ if (mWindow != null || mWindowless) {
+ mStarted = true;
+ try {
+ onDreamingStarted();
+ } finally {
try {
- onDreamingStarted();
- } finally {
- try {
- started.sendResult(null);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ started.sendResult(null);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
- });
+ };
+
+ // We need to defer calling onDreamingStarted until after the activity is created.
+ // If the dream is windowless, we can call it immediately. Otherwise, we wait
+ // for the DreamActivity to report onActivityCreated via
+ // DreamServiceWrapper.onActivityCreated.
+ if (!mWindowless) {
+ Intent i = new Intent(this, DreamActivity.class);
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
+
+ try {
+ if (!ActivityTaskManager.getService().startDreamActivity(i)) {
+ detach();
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not connect to activity task manager to start dream activity");
+ e.rethrowFromSystemServer();
+ }
+ } else {
+ mDispatchAfterOnAttachedToWindow.run();
+ }
+ }
+
+ private void onWindowCreated(Window w) {
+ mWindow = w;
+ mWindow.setCallback(this);
+ mWindow.setType(TYPE_DREAM);
+ mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+
+ WindowManager.LayoutParams lp = mWindow.getAttributes();
+ lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
+ lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+ | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
+ | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
+ );
+ mWindow.setAttributes(lp);
+ // Workaround: Currently low-profile and in-window system bar backgrounds don't go
+ // along well. Dreams usually don't need such bars anyways, so disable them by default.
+ mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+
+ applySystemUiVisibilityFlags(
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
+
+ mWindow.getDecorView().addOnAttachStateChangeListener(
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mDispatchAfterOnAttachedToWindow.run();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ finish();
+ }
+ });
}
private boolean getWindowFlagValue(int flag, boolean defaultValue) {
@@ -1131,10 +1151,10 @@
/** @hide */
protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print(TAG + ": ");
- if (mWindowToken == null) {
+ if (mFinished) {
pw.println("stopped");
} else {
- pw.println("running (token=" + mWindowToken + ")");
+ pw.println("running (dreamToken=" + mDreamToken + ")");
}
pw.println(" window: " + mWindow);
pw.print(" flags:");
@@ -1156,36 +1176,32 @@
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
- private final class DreamServiceWrapper extends IDreamService.Stub {
+ /**
+ * The DreamServiceWrapper is used as a gateway to the system_server, where DreamController
+ * uses it to control the DreamService. It is also used to receive callbacks from the
+ * DreamActivity.
+ */
+ final class DreamServiceWrapper extends IDreamService.Stub {
@Override
- public void attach(final IBinder windowToken, final boolean canDoze,
+ public void attach(final IBinder dreamToken, final boolean canDoze,
IRemoteCallback started) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- DreamService.this.attach(windowToken, canDoze, started);
- }
- });
+ mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started));
}
@Override
public void detach() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- DreamService.this.detach();
- }
- });
+ mHandler.post(DreamService.this::detach);
}
@Override
public void wakeUp() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- DreamService.this.wakeUp(true /*fromSystem*/);
- }
- });
+ mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
+ }
+
+ /** @hide */
+ void onActivityCreated(DreamActivity a) {
+ mActivity = a;
+ onWindowCreated(a.getWindow());
}
}
}
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1c6aba7..7690b94 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1612,6 +1612,7 @@
<java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
<java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
<java-symbol type="style" name="Theme.IconMenu" />
+ <java-symbol type="style" name="Theme.Dream" />
<java-symbol type="style" name="Theme.DeviceDefault.VoiceInteractionSession" />
<java-symbol type="style" name="Pointer" />
<java-symbol type="style" name="LargePointer" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 5d9cb48..2ef0c92 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -701,6 +701,11 @@
<item name="windowNoDisplay">true</item>
</style>
+ <style name="Theme.Dream">
+ <item name="windowBackground">@null</item>
+ <item name="windowDisablePreview">true</item>
+ </style>
+
<!-- Default theme for dialog windows and activities (on API level 10 and lower),
which is used by the
{@link android.app.Dialog} class. This changes the window to be
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index fbad8de..5320453 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -16,9 +16,6 @@
package com.android.server.dreams;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -27,10 +24,10 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.IBinder.DeathRecipient;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
@@ -38,15 +35,14 @@
import android.service.dreams.IDreamService;
import android.util.Slog;
import android.view.IWindowManager;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
import java.io.PrintWriter;
import java.util.NoSuchElementException;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-
/**
* Internal controller for starting and stopping the current dream and managing related state.
*
@@ -86,12 +82,9 @@
}
};
- private final Runnable mStopStubbornDreamRunnable = new Runnable() {
- @Override
- public void run() {
- Slog.w(TAG, "Stubborn dream did not finish itself in the time allotted");
- stopDream(true /*immediate*/);
- }
+ private final Runnable mStopStubbornDreamRunnable = () -> {
+ Slog.w(TAG, "Stubborn dream did not finish itself in the time allotted");
+ stopDream(true /*immediate*/);
};
public DreamController(Context context, Handler handler, Listener listener) {
@@ -140,14 +133,6 @@
MetricsLogger.visible(mContext,
mCurrentDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);
- try {
- mIWindowManager.addWindowToken(token, TYPE_DREAM, DEFAULT_DISPLAY);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Unable to add window token for dream.", ex);
- stopDream(true /*immediate*/);
- return;
- }
-
Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -216,9 +201,6 @@
}
if (oldDream.mService != null) {
- // Tell the dream that it's being stopped so that
- // it can shut down nicely before we yank its window token out from
- // under it.
try {
oldDream.mService.detach();
} catch (RemoteException ex) {
@@ -238,18 +220,7 @@
}
oldDream.releaseWakeLockIfNeeded();
- try {
- mIWindowManager.removeWindowToken(oldDream.mToken, DEFAULT_DISPLAY);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Error removing window token for dream.", ex);
- }
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDreamStopped(oldDream.mToken);
- }
- });
+ mHandler.post(() -> mListener.onDreamStopped(oldDream.mToken));
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -313,13 +284,10 @@
// May be called on any thread.
@Override
public void binderDied() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mService = null;
- if (mCurrentDream == DreamRecord.this) {
- stopDream(true /*immediate*/);
- }
+ mHandler.post(() -> {
+ mService = null;
+ if (mCurrentDream == DreamRecord.this) {
+ stopDream(true /*immediate*/);
}
});
}
@@ -327,16 +295,13 @@
// May be called on any thread.
@Override
public void onServiceConnected(ComponentName name, final IBinder service) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mConnected = true;
- if (mCurrentDream == DreamRecord.this && mService == null) {
- attach(IDreamService.Stub.asInterface(service));
- // Wake lock will be released once dreaming starts.
- } else {
- releaseWakeLockIfNeeded();
- }
+ mHandler.post(() -> {
+ mConnected = true;
+ if (mCurrentDream == DreamRecord.this && mService == null) {
+ attach(IDreamService.Stub.asInterface(service));
+ // Wake lock will be released once dreaming starts.
+ } else {
+ releaseWakeLockIfNeeded();
}
});
}
@@ -344,13 +309,10 @@
// May be called on any thread.
@Override
public void onServiceDisconnected(ComponentName name) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mService = null;
- if (mCurrentDream == DreamRecord.this) {
- stopDream(true /*immediate*/);
- }
+ mHandler.post(() -> {
+ mService = null;
+ if (mCurrentDream == DreamRecord.this) {
+ stopDream(true /*immediate*/);
}
});
}
@@ -373,4 +335,4 @@
}
};
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 3052e3c..a74be13 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -268,6 +268,10 @@
}
}
+ private ComponentName getActiveDreamComponentInternal(boolean doze) {
+ return chooseDreamForUser(doze, ActivityManager.getCurrentUser());
+ }
+
private ComponentName chooseDreamForUser(boolean doze, int userId) {
if (doze) {
ComponentName dozeComponent = getDozeComponent(userId);
@@ -671,6 +675,11 @@
public boolean isDreaming() {
return isDreamingInternal();
}
+
+ @Override
+ public ComponentName getActiveDreamComponent(boolean doze) {
+ return getActiveDreamComponentInternal(doze);
+ }
}
private final Runnable mSystemPropertiesChanged = new Runnable() {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a467e73..5603a3f 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -335,6 +335,7 @@
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
boolean allowBackgroundActivityStart;
+ boolean isDream;
/**
* If set to {@code true}, allows this activity start to look into
@@ -386,6 +387,7 @@
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
allowBackgroundActivityStart = false;
+ isDream = false;
}
/**
@@ -426,6 +428,7 @@
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
allowBackgroundActivityStart = request.allowBackgroundActivityStart;
+ isDream = request.isDream;
}
/**
@@ -969,7 +972,7 @@
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
- intent);
+ request.isDream, intent);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
@@ -1179,13 +1182,18 @@
boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
final String callingPackage, int realCallingUid, int realCallingPid,
WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart, Intent intent) {
+ boolean allowBackgroundActivityStart, boolean isDream, Intent intent) {
// don't abort for the most important UIDs
final int callingAppId = UserHandle.getAppId(callingUid);
if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) {
return false;
}
+
+ // don't abort if this is the dream activity
+ if (isDream) {
+ return false;
+ }
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow =
@@ -2669,6 +2677,11 @@
return this;
}
+ ActivityStarter setIsDream(boolean isDream) {
+ mRequest.isDream = isDream;
+ return this;
+ }
+
void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9458939..693a5e4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -212,6 +212,8 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
+import android.service.dreams.DreamActivity;
+import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
import android.sysprop.DisplayProperties;
@@ -1231,6 +1233,52 @@
}
@Override
+ public boolean startDreamActivity(Intent intent) {
+ final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid());
+ final long origId = Binder.clearCallingIdentity();
+
+ // The dream activity is only called for non-doze dreams.
+ final ComponentName currentDream = LocalServices.getService(DreamManagerInternal.class)
+ .getActiveDreamComponent(/* doze= */ false);
+
+ if (currentDream == null || currentDream.getPackageName() == null
+ || !currentDream.getPackageName().equals(process.mInfo.packageName)) {
+ Slog.e(TAG, "Calling package is not the current dream package. "
+ + "Aborting startDreamActivity...");
+ return false;
+ }
+
+ final ActivityInfo a = new ActivityInfo();
+ a.theme = com.android.internal.R.style.Theme_Dream;
+ a.exported = true;
+ a.name = DreamActivity.class.getName();
+
+
+ a.packageName = process.mInfo.packageName;
+ a.applicationInfo = process.mInfo;
+ a.processName = process.mInfo.processName;
+ a.uiOptions = process.mInfo.uiOptions;
+ a.taskAffinity = "android:" + a.packageName + "/dream";
+ a.enabled = true;
+ a.launchMode = ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+
+ a.persistableMode = ActivityInfo.PERSIST_NEVER;
+ a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+ a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+
+ try {
+ getActivityStartController().obtainStarter(intent, "dream")
+ .setActivityInfo(a)
+ .setIsDream(true)
+ .execute();
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
@@ -2403,7 +2451,7 @@
final ActivityStarter starter = getActivityStartController().obtainStarter(
null /* intent */, "moveTaskToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
- -1, callerApp, null, false, null)) {
+ -1, callerApp, null, false, false, null)) {
if (!isBackgroundActivityStartsEnabled()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 8fa8119..4cce212 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -111,7 +111,7 @@
final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
null /* intent */, "moveToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
- callingPackage, -1, -1, callerApp, null, false, null)) {
+ callingPackage, -1, -1, callerApp, null, false, false, null)) {
if (!mService.isBackgroundActivityStartsEnabled()) {
return;
}