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);
|
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,
|
||||||
|
|||||||
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;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user