Make DreamService use an Activity am: 6861e91b84 am: b378a53f8b am: 907c0b7873
Change-Id: Iab2666e53cfb4c6e74246f074d578ef4831ff351
This commit is contained in:
@@ -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,
|
||||
|
||||
59
core/java/android/service/dreams/DreamActivity.java
Normal file
59
core/java/android/service/dreams/DreamActivity.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
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 @@ 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -335,6 +335,7 @@ class ActivityStarter {
|
||||
int filterCallingUid;
|
||||
PendingIntentRecord originatingPendingIntent;
|
||||
boolean allowBackgroundActivityStart;
|
||||
boolean isDream;
|
||||
|
||||
/**
|
||||
* If set to {@code true}, allows this activity start to look into
|
||||
@@ -386,6 +387,7 @@ class ActivityStarter {
|
||||
filterCallingUid = UserHandle.USER_NULL;
|
||||
originatingPendingIntent = null;
|
||||
allowBackgroundActivityStart = false;
|
||||
isDream = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,6 +428,7 @@ class ActivityStarter {
|
||||
filterCallingUid = request.filterCallingUid;
|
||||
originatingPendingIntent = request.originatingPendingIntent;
|
||||
allowBackgroundActivityStart = request.allowBackgroundActivityStart;
|
||||
isDream = request.isDream;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -969,7 +972,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);
|
||||
}
|
||||
@@ -1179,13 +1182,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 =
|
||||
@@ -2669,6 +2677,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);
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
|
||||
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user