diff options
| author | 2019-08-21 10:20:23 +0200 | |
|---|---|---|
| committer | 2020-02-25 07:56:28 +0000 | |
| commit | 6861e91b84fb444f6a04256bd5d564730660efeb (patch) | |
| tree | 5c55c1f38cd14ac6bedaeb4f526a8d7fc954d9ee | |
| parent | a8e46412963a1ba466d1a1f180eef703d262e008 (diff) | |
Make DreamService use an Activity
Currently, the DreamService uses a floating Window to display the
content of the dream on the screen. This introduces difficulties in the
interactions with the Assistant application, which is an activity.
By design, if the Assistant is invoked while the device is dreaming, the
Assistant should be shown on top. However, since floating windows are
always drawn on top of all activities, the Assistant can't be shown on
top of the Dream.
Here, we migrate the implementation of the DreamService to use an
Activity (DreamActivity). Since the screensaver application is not part
of the framework, we can't declare the activity in their AndroidManifest.xml.
Therefore, we start the dream activity with a dedicated method in
ActivityTaskManagerService.
Bug: 133216167
Test: 1. m && ./vendor/google/tools/flashall
2. Go to Settings > Device Preferences > Screensaver > Start now
3. Verify dream appears
4. Click any key to wake up the dream
5. Verify that dream disappears
Merged-In: I8dff0a124cd1b41fb925a73528305431b49ee06d
Change-Id: I8dff0a124cd1b41fb925a73528305431b49ee06d
(cherry picked from commit 148478a85e25c86e4b333295dec03aadedc17e1a)
9 files changed, 264 insertions, 132 deletions
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 5b61402314c4..a55b2c832e41 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -98,6 +98,14 @@ interface IActivityTaskManager { 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 000000000000..8cdd24e0884d --- /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/DreamService.java b/core/java/android/service/dreams/DreamService.java index 96a89bcd0120..b31238ca25ca 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.ViewGroup; 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 class DreamService extends Service implements Window.Callback { */ 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 @@ public class DreamService extends Service implements Window.Callback { 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)); } /** @@ -670,14 +676,14 @@ public class DreamService extends Service implements Window.Callback { } 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 +706,7 @@ public class DreamService extends Service implements Window.Callback { if (mDozing) { mDozing = false; try { - mSandman.stopDozing(mWindowToken); + mDreamManager.stopDozing(mDreamToken); } catch (RemoteException ex) { // system server died } @@ -875,14 +881,15 @@ public class DreamService extends Service implements Window.Callback { * </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 +902,29 @@ public class DreamService extends Service implements Window.Callback { 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."); + return; + } + + // In case the activity is not finished yet, do it now. This can happen if someone calls + // finish() directly, without going through wakeUp(). + if (!mActivity.isFinishing()) { + 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 +954,11 @@ public class DreamService extends Service implements Window.Callback { // 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 +993,12 @@ public class DreamService extends Service implements Window.Callback { 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(); } - 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 @@ public class DreamService extends Service implements Window.Callback { * * 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); + mDispatchAfterOnAttachedToWindow = () -> { + if (mWindow != null || mWindowless) { + mStarted = true; + try { + onDreamingStarted(); + } finally { + try { + started.sendResult(null); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + }; - applySystemUiVisibilityFlags( - (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0), - View.SYSTEM_UI_FLAG_LOW_PROFILE); + // 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 { - 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; + 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(); } - // 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; - try { - onDreamingStarted(); - } finally { - try { - started.sendResult(null); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + } + + 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 @@ public class DreamService extends Service implements Window.Callback { /** @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,11 +1176,16 @@ public class DreamService extends Service implements Window.Callback { 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(() -> DreamService.this.attach(windowToken, canDoze, started)); + mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started)); } @Override @@ -1172,5 +1197,11 @@ public class DreamService extends Service implements Window.Callback { public void wakeUp() { 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 d5954596535d..b2b32418afa0 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 5d9cb48aa5ed..2ef0c927cc61 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -701,6 +701,11 @@ please see themes_device_defaults.xml. <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 2ed4f390c973..532045320988 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 static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.LayoutParams.TYPE_DREAM; - import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -136,14 +133,6 @@ final class DreamController { 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); @@ -212,9 +201,6 @@ final class DreamController { } 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) { @@ -234,12 +220,6 @@ final class DreamController { } oldDream.releaseWakeLockIfNeeded(); - try { - mIWindowManager.removeWindowToken(oldDream.mToken, DEFAULT_DISPLAY); - } catch (RemoteException ex) { - Slog.w(TAG, "Error removing window token for dream.", ex); - } - mHandler.post(() -> mListener.onDreamStopped(oldDream.mToken)); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); @@ -355,4 +335,4 @@ final class DreamController { } }; } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 600a125cdf43..4ea5b2dd354b 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -336,6 +336,7 @@ class ActivityStarter { int filterCallingUid; PendingIntentRecord originatingPendingIntent; boolean allowBackgroundActivityStart; + boolean isDream; /** * If set to {@code true}, allows this activity start to look into @@ -387,6 +388,7 @@ class ActivityStarter { filterCallingUid = UserHandle.USER_NULL; originatingPendingIntent = null; allowBackgroundActivityStart = false; + isDream = false; } /** @@ -427,6 +429,7 @@ class ActivityStarter { filterCallingUid = request.filterCallingUid; originatingPendingIntent = request.originatingPendingIntent; allowBackgroundActivityStart = request.allowBackgroundActivityStart; + isDream = request.isDream; } /** @@ -970,7 +973,7 @@ class ActivityStarter { restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, realCallingUid, realCallingPid, callerApp, request.originatingPendingIntent, request.allowBackgroundActivityStart, - intent); + request.isDream, intent); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } @@ -1180,13 +1183,18 @@ class ActivityStarter { 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 = @@ -2686,6 +2694,11 @@ class ActivityStarter { 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 5392257ae0b0..dfc9aa806373 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -212,6 +212,7 @@ import android.os.WorkSource; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.Settings; +import android.service.dreams.DreamActivity; import android.service.voice.IVoiceInteractionSession; import android.service.voice.VoiceInteractionManagerInternal; import android.sysprop.DisplayProperties; @@ -1231,6 +1232,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public boolean startDreamActivity(Intent intent) { + final ActivityInfo a = new ActivityInfo(); + a.theme = com.android.internal.R.style.Theme_Dream; + a.exported = true; + a.name = DreamActivity.class.getName(); + + final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid()); + + 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; + + final long origId = Binder.clearCallingIdentity(); + 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 +2438,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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 8fa811915fc2..4cce212cb779 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 @@ class AppTaskImpl extends IAppTask.Stub { 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; } |