Loading core/java/android/app/IActivityTaskManager.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -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, Loading core/java/android/service/dreams/DreamActivity.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * 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); } } } core/java/android/service/dreams/DreamManagerInternal.java +11 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.service.dreams; import android.content.ComponentName; /** * Dream manager local system service interface. * Loading @@ -42,4 +44,13 @@ public abstract class DreamManagerInternal { * Called by the power manager to determine whether a dream is running. */ public abstract boolean isDreaming(); /** * Called by the ActivityTaskManagerService to verify that the startDreamActivity * request comes from the current active dream component. * * @param doze If true returns the current active doze component. Otherwise, returns the * active dream component. */ public abstract ComponentName getActiveDreamComponent(boolean doze); } core/java/android/service/dreams/DreamService.java +141 −125 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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)); } /** Loading Loading @@ -602,6 +608,8 @@ public class DreamService extends Service implements Window.Callback { * Marks this dream as windowless. Only available to doze dreams. * * @hide * * TODO: Remove @UnsupportedAppUsage. */ @UnsupportedAppUsage public void setWindowless(boolean windowless) { Loading Loading @@ -670,14 +678,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 } Loading @@ -700,7 +708,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 } Loading Loading @@ -875,14 +883,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; } /** Loading @@ -895,21 +904,26 @@ 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."); } else if (!mActivity.isFinishing()) { // In case the activity is not finished yet, do it now. This can happen if someone calls // finish() directly, without going through wakeUp(). mActivity.finishAndRemoveTask(); return; } if (!mFinished) { mFinished = true; if (mWindowToken == null) { Slog.w(TAG, "Finish was called before the dream was attached."); } else { try { mSandman.finishSelf(mWindowToken, true /*immediate*/); // 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 } } /** Loading Loading @@ -938,11 +952,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 } Loading Loading @@ -977,69 +991,98 @@ 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(); } else { finish(); } if (mWindowToken != null) { // the following will print a log message if it finds any other leaked windows WindowManagerGlobal.getInstance().closeAll(mWindowToken, this.getClass().getName(), "Dream"); mWindowToken = null; mDreamToken = null; mCanDoze = false; } } /** * Called when the Dream is ready to be shown. * * 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"); } mDispatchAfterOnAttachedToWindow = () -> { if (mWindow != null || mWindowless) { mStarted = true; try { onDreamingStarted(); } finally { try { 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) { mWindow = new PhoneWindow(this); 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); 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 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0) | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0) ); Loading @@ -1047,44 +1090,21 @@ public class DreamService extends Service implements Window.Callback { // 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() { mWindow.getDecorView().addOnAttachStateChangeListener( new View.OnAttachStateChangeListener() { @Override public void run() { if (mWindow != null || mWindowless) { if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()"); mStarted = true; try { onDreamingStarted(); } finally { try { started.sendResult(null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } public void onViewAttachedToWindow(View v) { mDispatchAfterOnAttachedToWindow.run(); } @Override public void onViewDetachedFromWindow(View v) { finish(); } }); } Loading Loading @@ -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:"); Loading @@ -1156,36 +1176,32 @@ 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(new Runnable() { @Override public void run() { DreamService.this.attach(windowToken, canDoze, started); } }); mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started)); } @Override public void detach() { mHandler.post(new Runnable() { @Override public void run() { DreamService.this.detach(); } }); mHandler.post(DreamService.this::detach); } @Override public void wakeUp() { mHandler.post(new Runnable() { @Override public void run() { DreamService.this.wakeUp(true /*fromSystem*/); mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/)); } }); /** @hide */ void onActivityCreated(DreamActivity a) { mActivity = a; onWindowCreated(a.getWindow()); } } } core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading Loading
core/java/android/app/IActivityTaskManager.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
core/java/android/service/dreams/DreamActivity.java 0 → 100644 +59 −0 Original line number Diff line number Diff line /* * 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); } } }
core/java/android/service/dreams/DreamManagerInternal.java +11 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.service.dreams; import android.content.ComponentName; /** * Dream manager local system service interface. * Loading @@ -42,4 +44,13 @@ public abstract class DreamManagerInternal { * Called by the power manager to determine whether a dream is running. */ public abstract boolean isDreaming(); /** * Called by the ActivityTaskManagerService to verify that the startDreamActivity * request comes from the current active dream component. * * @param doze If true returns the current active doze component. Otherwise, returns the * active dream component. */ public abstract ComponentName getActiveDreamComponent(boolean doze); }
core/java/android/service/dreams/DreamService.java +141 −125 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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)); } /** Loading Loading @@ -602,6 +608,8 @@ public class DreamService extends Service implements Window.Callback { * Marks this dream as windowless. Only available to doze dreams. * * @hide * * TODO: Remove @UnsupportedAppUsage. */ @UnsupportedAppUsage public void setWindowless(boolean windowless) { Loading Loading @@ -670,14 +678,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 } Loading @@ -700,7 +708,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 } Loading Loading @@ -875,14 +883,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; } /** Loading @@ -895,21 +904,26 @@ 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."); } else if (!mActivity.isFinishing()) { // In case the activity is not finished yet, do it now. This can happen if someone calls // finish() directly, without going through wakeUp(). mActivity.finishAndRemoveTask(); return; } if (!mFinished) { mFinished = true; if (mWindowToken == null) { Slog.w(TAG, "Finish was called before the dream was attached."); } else { try { mSandman.finishSelf(mWindowToken, true /*immediate*/); // 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 } } /** Loading Loading @@ -938,11 +952,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 } Loading Loading @@ -977,69 +991,98 @@ 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(); } else { finish(); } if (mWindowToken != null) { // the following will print a log message if it finds any other leaked windows WindowManagerGlobal.getInstance().closeAll(mWindowToken, this.getClass().getName(), "Dream"); mWindowToken = null; mDreamToken = null; mCanDoze = false; } } /** * Called when the Dream is ready to be shown. * * 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"); } mDispatchAfterOnAttachedToWindow = () -> { if (mWindow != null || mWindowless) { mStarted = true; try { onDreamingStarted(); } finally { try { 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) { mWindow = new PhoneWindow(this); 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); 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 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0) | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0) ); Loading @@ -1047,44 +1090,21 @@ public class DreamService extends Service implements Window.Callback { // 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() { mWindow.getDecorView().addOnAttachStateChangeListener( new View.OnAttachStateChangeListener() { @Override public void run() { if (mWindow != null || mWindowless) { if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()"); mStarted = true; try { onDreamingStarted(); } finally { try { started.sendResult(null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } public void onViewAttachedToWindow(View v) { mDispatchAfterOnAttachedToWindow.run(); } @Override public void onViewDetachedFromWindow(View v) { finish(); } }); } Loading Loading @@ -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:"); Loading @@ -1156,36 +1176,32 @@ 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(new Runnable() { @Override public void run() { DreamService.this.attach(windowToken, canDoze, started); } }); mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started)); } @Override public void detach() { mHandler.post(new Runnable() { @Override public void run() { DreamService.this.detach(); } }); mHandler.post(DreamService.this::detach); } @Override public void wakeUp() { mHandler.post(new Runnable() { @Override public void run() { DreamService.this.wakeUp(true /*fromSystem*/); mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/)); } }); /** @hide */ void onActivityCreated(DreamActivity a) { mActivity = a; onWindowCreated(a.getWindow()); } } }
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading