Make DreamService use an Activity am: 6861e91b84

Change-Id: I38393018a7afd2accbf20baae755db21183ab42c
This commit is contained in:
Automerger Merge Worker
2020-02-25 10:25:55 +00:00
9 changed files with 266 additions and 134 deletions

View File

@@ -98,6 +98,14 @@ interface IActivityTaskManager {
in ProfilerInfo profilerInfo, in Bundle options, int userId); in ProfilerInfo profilerInfo, in Bundle options, int userId);
boolean startNextMatchingActivity(in IBinder callingActivity, boolean startNextMatchingActivity(in IBinder callingActivity,
in Intent intent, in Bundle options); 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, int startActivityIntentSender(in IApplicationThread caller,
in IIntentSender target, in IBinder whitelistToken, in Intent fillInIntent, in IIntentSender target, in IBinder whitelistToken, in Intent fillInIntent,
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,

View File

@@ -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);
}
}
}

View File

@@ -15,25 +15,29 @@
*/ */
package android.service.dreams; package android.service.dreams;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import android.annotation.IdRes; import android.annotation.IdRes;
import android.annotation.LayoutRes; import android.annotation.LayoutRes;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.Service; import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent; import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.IRemoteCallback; import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.util.Log;
import android.util.MathUtils; import android.util.MathUtils;
import android.util.Slog; import android.util.Slog;
import android.view.ActionMode; import android.view.ActionMode;
@@ -48,10 +52,8 @@ import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils.Dump; 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"; public static final String DREAM_META_DATA = "android.service.dream";
private final IDreamManager mSandman; private final IDreamManager mDreamManager;
private final Handler mHandler = new Handler(); private final Handler mHandler = new Handler(Looper.getMainLooper());
private IBinder mWindowToken; private IBinder mDreamToken;
private Window mWindow; private Window mWindow;
private Activity mActivity;
private boolean mInteractive; private boolean mInteractive;
private boolean mLowProfile = true; private boolean mLowProfile = true;
private boolean mFullscreen; private boolean mFullscreen;
@@ -195,8 +198,11 @@ public class DreamService extends Service implements Window.Callback {
private boolean mDebug = false; private boolean mDebug = false;
private DreamServiceWrapper mDreamServiceWrapper;
private Runnable mDispatchAfterOnAttachedToWindow;
public DreamService() { 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() { private void updateDoze() {
if (mWindowToken == null) { if (mDreamToken == null) {
Slog.w(TAG, "Updating doze without a window token."); Slog.w(TAG, "Updating doze without a dream token.");
return; return;
} }
if (mDozing) { if (mDozing) {
try { try {
mSandman.startDozing(mWindowToken, mDozeScreenState, mDozeScreenBrightness); mDreamManager.startDozing(mDreamToken, mDozeScreenState, mDozeScreenBrightness);
} catch (RemoteException ex) { } catch (RemoteException ex) {
// system server died // system server died
} }
@@ -700,7 +706,7 @@ public class DreamService extends Service implements Window.Callback {
if (mDozing) { if (mDozing) {
mDozing = false; mDozing = false;
try { try {
mSandman.stopDozing(mWindowToken); mDreamManager.stopDozing(mDreamToken);
} catch (RemoteException ex) { } catch (RemoteException ex) {
// system server died // system server died
} }
@@ -875,14 +881,15 @@ public class DreamService extends Service implements Window.Callback {
* </p> * </p>
*/ */
public void onWakeUp() { public void onWakeUp() {
finish(); mActivity.finishAndRemoveTask();
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final IBinder onBind(Intent intent) { public final IBinder onBind(Intent intent) {
if (mDebug) Slog.v(TAG, "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() { public final void finish() {
if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished); 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) { if (!mFinished) {
mFinished = true; mFinished = true;
if (mWindowToken == null) { try {
Slog.w(TAG, "Finish was called before the dream was attached."); // finishSelf will unbind the dream controller from the dream service. This will
} else { // trigger DreamService.this.onDestroy and DreamService.this will die.
try { mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
mSandman.finishSelf(mWindowToken, true /*immediate*/); } catch (RemoteException ex) {
} catch (RemoteException ex) { // system server died
// 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 // Now tell the system we are waking gently, unless we already told
// it we were finishing immediately. // it we were finishing immediately.
if (!fromSystem && !mFinished) { if (!fromSystem && !mFinished) {
if (mWindowToken == null) { if (mActivity == null) {
Slog.w(TAG, "WakeUp was called before the dream was attached."); Slog.w(TAG, "WakeUp was called before the dream was attached.");
} else { } else {
try { try {
mSandman.finishSelf(mWindowToken, false /*immediate*/); mDreamManager.finishSelf(mDreamToken, false /*immediate*/);
} catch (RemoteException ex) { } catch (RemoteException ex) {
// system server died // system server died
} }
@@ -977,20 +993,12 @@ public class DreamService extends Service implements Window.Callback {
onDreamingStopped(); onDreamingStopped();
} }
if (mWindow != null) { if (mActivity != null && !mActivity.isFinishing()) {
// force our window to be removed synchronously mActivity.finishAndRemoveTask();
if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
mWindow = null;
} }
if (mWindowToken != null) { mDreamToken = null;
// the following will print a log message if it finds any other leaked windows mCanDoze = false;
WindowManagerGlobal.getInstance().closeAll(mWindowToken,
this.getClass().getName(), "Dream");
mWindowToken = null;
mCanDoze = false;
}
} }
/** /**
@@ -998,95 +1006,107 @@ public class DreamService extends Service implements Window.Callback {
* *
* Must run on mHandler. * 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. * @param started A callback that will be invoked once onDreamingStarted has completed.
*/ */
private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) { private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) {
if (mWindowToken != null) { if (mActivity != null) {
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken); Slog.e(TAG, "attach() called when dream with token=" + mDreamToken
+ " already attached");
return; return;
} }
if (mFinished || mWaking) { if (mFinished || mWaking) {
Slog.w(TAG, "attach() called after dream already finished"); Slog.w(TAG, "attach() called after dream already finished");
try { try {
mSandman.finishSelf(windowToken, true /*immediate*/); mDreamManager.finishSelf(dreamToken, true /*immediate*/);
} catch (RemoteException ex) { } catch (RemoteException ex) {
// system server died // system server died
} }
return; return;
} }
mWindowToken = windowToken; mDreamToken = dreamToken;
mCanDoze = canDoze; mCanDoze = canDoze;
if (mWindowless && !mCanDoze) { if (mWindowless && !mCanDoze) {
throw new IllegalStateException("Only doze dreams can be windowless"); 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", mDispatchAfterOnAttachedToWindow = () -> {
windowToken, WindowManager.LayoutParams.TYPE_DREAM)); if (mWindow != null || mWindowless) {
mStarted = true;
WindowManager.LayoutParams lp = mWindow.getAttributes(); try {
lp.type = WindowManager.LayoutParams.TYPE_DREAM; onDreamingStarted();
lp.token = windowToken; } finally {
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;
try { try {
onDreamingStarted(); started.sendResult(null);
} finally { } catch (RemoteException e) {
try { 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) { private boolean getWindowFlagValue(int flag, boolean defaultValue) {
@@ -1131,10 +1151,10 @@ public class DreamService extends Service implements Window.Callback {
/** @hide */ /** @hide */
protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) { protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print(TAG + ": "); pw.print(TAG + ": ");
if (mWindowToken == null) { if (mFinished) {
pw.println("stopped"); pw.println("stopped");
} else { } else {
pw.println("running (token=" + mWindowToken + ")"); pw.println("running (dreamToken=" + mDreamToken + ")");
} }
pw.println(" window: " + mWindow); pw.println(" window: " + mWindow);
pw.print(" flags:"); 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); 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 @Override
public void attach(final IBinder windowToken, final boolean canDoze, public void attach(final IBinder dreamToken, final boolean canDoze,
IRemoteCallback started) { IRemoteCallback started) {
mHandler.post(() -> DreamService.this.attach(windowToken, canDoze, started)); mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started));
} }
@Override @Override
@@ -1172,5 +1197,11 @@ public class DreamService extends Service implements Window.Callback {
public void wakeUp() { public void wakeUp() {
mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/)); mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
} }
/** @hide */
void onActivityCreated(DreamActivity a) {
mActivity = a;
onWindowCreated(a.getWindow());
}
} }
} }

View File

@@ -1612,6 +1612,7 @@
<java-symbol type="style" name="TextAppearance.SlidingTabNormal" /> <java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
<java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" /> <java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
<java-symbol type="style" name="Theme.IconMenu" /> <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="Theme.DeviceDefault.VoiceInteractionSession" />
<java-symbol type="style" name="Pointer" /> <java-symbol type="style" name="Pointer" />
<java-symbol type="style" name="LargePointer" /> <java-symbol type="style" name="LargePointer" />

View File

@@ -701,6 +701,11 @@ please see themes_device_defaults.xml.
<item name="windowNoDisplay">true</item> <item name="windowNoDisplay">true</item>
</style> </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), <!-- Default theme for dialog windows and activities (on API level 10 and lower),
which is used by the which is used by the
{@link android.app.Dialog} class. This changes the window to be {@link android.app.Dialog} class. This changes the window to be

View File

@@ -16,9 +16,6 @@
package com.android.server.dreams; 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.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -136,14 +133,6 @@ final class DreamController {
MetricsLogger.visible(mContext, MetricsLogger.visible(mContext,
mCurrentDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING); 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 intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name); intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -212,9 +201,6 @@ final class DreamController {
} }
if (oldDream.mService != null) { 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 { try {
oldDream.mService.detach(); oldDream.mService.detach();
} catch (RemoteException ex) { } catch (RemoteException ex) {
@@ -234,12 +220,6 @@ final class DreamController {
} }
oldDream.releaseWakeLockIfNeeded(); 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)); mHandler.post(() -> mListener.onDreamStopped(oldDream.mToken));
} finally { } finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER); Trace.traceEnd(Trace.TRACE_TAG_POWER);
@@ -355,4 +335,4 @@ final class DreamController {
} }
}; };
} }
} }

View File

@@ -335,6 +335,7 @@ class ActivityStarter {
int filterCallingUid; int filterCallingUid;
PendingIntentRecord originatingPendingIntent; PendingIntentRecord originatingPendingIntent;
boolean allowBackgroundActivityStart; boolean allowBackgroundActivityStart;
boolean isDream;
/** /**
* If set to {@code true}, allows this activity start to look into * If set to {@code true}, allows this activity start to look into
@@ -386,6 +387,7 @@ class ActivityStarter {
filterCallingUid = UserHandle.USER_NULL; filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null; originatingPendingIntent = null;
allowBackgroundActivityStart = false; allowBackgroundActivityStart = false;
isDream = false;
} }
/** /**
@@ -426,6 +428,7 @@ class ActivityStarter {
filterCallingUid = request.filterCallingUid; filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent; originatingPendingIntent = request.originatingPendingIntent;
allowBackgroundActivityStart = request.allowBackgroundActivityStart; allowBackgroundActivityStart = request.allowBackgroundActivityStart;
isDream = request.isDream;
} }
/** /**
@@ -969,7 +972,7 @@ class ActivityStarter {
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid, restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp, callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart, request.originatingPendingIntent, request.allowBackgroundActivityStart,
intent); request.isDream, intent);
} finally { } finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
} }
@@ -1179,13 +1182,18 @@ class ActivityStarter {
boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid, boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
final String callingPackage, int realCallingUid, int realCallingPid, final String callingPackage, int realCallingUid, int realCallingPid,
WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent, WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart, Intent intent) { boolean allowBackgroundActivityStart, boolean isDream, Intent intent) {
// don't abort for the most important UIDs // don't abort for the most important UIDs
final int callingAppId = UserHandle.getAppId(callingUid); final int callingAppId = UserHandle.getAppId(callingUid);
if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) { || callingAppId == Process.NFC_UID) {
return false; 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 // don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.getUidState(callingUid); final int callingUidProcState = mService.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow = final boolean callingUidHasAnyVisibleWindow =
@@ -2669,6 +2677,11 @@ class ActivityStarter {
return this; return this;
} }
ActivityStarter setIsDream(boolean isDream) {
mRequest.isDream = isDream;
return this;
}
void dump(PrintWriter pw, String prefix) { void dump(PrintWriter pw, String prefix) {
prefix = prefix + " "; prefix = prefix + " ";
pw.print(prefix); pw.print(prefix);

View File

@@ -212,6 +212,7 @@ import android.os.WorkSource;
import android.os.storage.IStorageManager; import android.os.storage.IStorageManager;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.provider.Settings; import android.provider.Settings;
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal; import android.service.voice.VoiceInteractionManagerInternal;
import android.sysprop.DisplayProperties; import android.sysprop.DisplayProperties;
@@ -1230,6 +1231,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 @Override
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage, public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
@@ -2403,7 +2438,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final ActivityStarter starter = getActivityStartController().obtainStarter( final ActivityStarter starter = getActivityStartController().obtainStarter(
null /* intent */, "moveTaskToFront"); null /* intent */, "moveTaskToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1, if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
-1, callerApp, null, false, null)) { -1, callerApp, null, false, false, null)) {
if (!isBackgroundActivityStartsEnabled()) { if (!isBackgroundActivityStartsEnabled()) {
return; return;
} }

View File

@@ -111,7 +111,7 @@ class AppTaskImpl extends IAppTask.Stub {
final ActivityStarter starter = mService.getActivityStartController().obtainStarter( final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
null /* intent */, "moveToFront"); null /* intent */, "moveToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
callingPackage, -1, -1, callerApp, null, false, null)) { callingPackage, -1, -1, callerApp, null, false, false, null)) {
if (!mService.isBackgroundActivityStartsEnabled()) { if (!mService.isBackgroundActivityStartsEnabled()) {
return; return;
} }