Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0601eb79 authored by Daniel Sandler's avatar Daniel Sandler Committed by Daniel Sandler
Browse files

Framework support for Android Dreams.

A Dream is an activity that is launched by the window
manager after a specified idle time. You might think of this
as a "screen saver", but with the same capacity for
interactivity as any other application.

The window manager maintains a timer (like the screen lock
timer) that is reset on userActivity; the timer is suspended
during wakelocks and when the screen is off.

When the timer elapses, the user's preferred dream module is
launched (by reading Settings.Secure.DREAM_COMPONENT, which
is configured through the Settings app UI).

Like a dock app, the user can install new dreams and a
single application package may contain multiple dream
activities. Unlike the dock mode, however, there is no
"screensaver mode" for the system to manage. This allows us
to offer the user the ability to run a dream at any time, in
addition to making the overall mechanism quite simple.

There is no public API for this facility.

There is, however, a useful/recommended base class for dream
activities in the support library (change I4559a958).

Change-Id: Ied691856f88cfa38a7aca496d015f9a595da72f2
parent 52ee3eb4
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -3736,6 +3736,23 @@ public final class Settings {
        public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
                "setup_prepaid_detection_redir_host";

        /**
         * The user's preferred "dream" (interactive screensaver) component.
         *
         * This component will be launched by the PhoneWindowManager after the user's chosen idle
         * timeout (specified by {@link #DREAM_TIMEOUT}).
         * @hide
         */
        public static final String DREAM_COMPONENT =
                "dream_component";

        /**
         * The delay before a "dream" is started (set to 0 to disable).
         * @hide
         */
        public static final String DREAM_TIMEOUT =
                "dream_timeout";

        /**
         * @hide
         */
+7 −1
Original line number Diff line number Diff line
@@ -866,7 +866,13 @@ public interface WindowManagerPolicy {
    public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
    
    /**
     * Called when we have stopped keeping the screen on because a window
     * Called when we have started keeping the screen on because a window
     * requesting this has become visible.
     */
    public void screenOnStartedLw();

    /**
     * Called when we have stopped keeping the screen on because the last window
     * requesting this is no longer visible.
     */
    public void screenOnStoppedLw();
+91 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.app.IUiModeManager;
import android.app.UiModeManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -344,6 +345,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    int mLockScreenTimeout;
    boolean mLockScreenTimerActive;

    // visual screen saver support
    int mScreenSaverTimeout;
    boolean mScreenSaverEnabled = false;

    // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
    int mEndcallBehavior;

@@ -399,6 +404,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
            resolver.registerContentObserver(Settings.System.getUriFor(
                    "fancy_rotation_anim"), false, this);
            resolver.registerContentObserver(Settings.System.getUriFor(
                    Settings.Secure.DREAM_TIMEOUT), false, this);
            updateSettings();
        }

@@ -832,6 +839,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                mHasSoftInput = hasSoftInput;
                updateRotation = true;
            }

            mScreenSaverTimeout = Settings.System.getInt(resolver,
                    Settings.Secure.DREAM_TIMEOUT, 0);
            mScreenSaverEnabled = true;
            updateScreenSaverTimeoutLocked();
        }
        if (updateRotation) {
            updateRotation(0);
@@ -2595,6 +2607,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            mScreenOn = false;
            updateOrientationListenerLp();
            updateLockScreenTimeout();
            updateScreenSaverTimeoutLocked();
        }
    }

@@ -2606,6 +2619,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            mScreenOn = true;
            updateOrientationListenerLp();
            updateLockScreenTimeout();
            updateScreenSaverTimeoutLocked();
        }
    }

@@ -2886,6 +2900,63 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                mStatusBarService.userActivity();
            } catch (RemoteException ex) {}
        }

        synchronized (mLock) {
            updateScreenSaverTimeoutLocked();
        }
    }

    Runnable mScreenSaverActivator = new Runnable() {
        public void run() {
            synchronized (this) {
                if (!(mScreenSaverEnabled && mScreenOn)) {
                    Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?");
                    return;
                }

                if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland");
                try {
                    String component = Settings.System.getString(
                            mContext.getContentResolver(), Settings.Secure.DREAM_COMPONENT);
                    if (component != null) {
                        ComponentName cn = ComponentName.unflattenFromString(component);
                        Intent intent = new Intent(Intent.ACTION_MAIN)
                            .setComponent(cn)
                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                                | Intent.FLAG_ACTIVITY_NO_USER_ACTION
                                | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        mContext.startActivity(intent);
                    } else {
                        Log.e(TAG, "Couldn't start screen saver: none selected");
                    }
                } catch (android.content.ActivityNotFoundException exc) {
                    // no screensaver? give up
                    Log.e(TAG, "Couldn't start screen saver: none installed");
                }
            }
        }
    };

    // Must call while holding mLock
    private void updateScreenSaverTimeoutLocked() {
        synchronized (mScreenSaverActivator) {
            mHandler.removeCallbacks(mScreenSaverActivator);
            if (mScreenSaverEnabled && mScreenOn && mScreenSaverTimeout > 0) {
                if (localLOGV)
                    Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now");
                mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout);
            } else {
                if (localLOGV) {
                    if (mScreenSaverTimeout == 0)
                        Log.v(TAG, "screen saver disabled by user");
                    else if (!mScreenOn)
                        Log.v(TAG, "screen saver disabled while screen off");
                    else
                        Log.v(TAG, "screen saver disabled by wakelock");
                }
            }
        }
    }

    Runnable mScreenLockTimeout = new Runnable() {
@@ -3081,11 +3152,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        return true;
    }
    
    public void screenOnStartedLw() {
        // The window manager has just grabbed a wake lock. This is our cue to disable the screen
        // saver.
        synchronized (mLock) {
            mScreenSaverEnabled = false;
        }
    }

    public void screenOnStoppedLw() {
        if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) {
        if (mPowerManager.isScreenOn()) {
            if (!mKeyguardMediator.isShowingAndNotHidden()) {
                long curTime = SystemClock.uptimeMillis();
                mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
            }

            synchronized (mLock) {
                // even if the keyguard is up, now that all the wakelocks have been released, we
                // should re-enable the screen saver
                mScreenSaverEnabled = true;
                updateScreenSaverTimeoutLocked();
            }
        }
    }

    public boolean allowKeyRepeat() {
+1 −0
Original line number Diff line number Diff line
@@ -8301,6 +8301,7 @@ public class WindowManagerService extends IWindowManager.Stub
        boolean state = mHoldingScreenWakeLock.isHeld();
        if (holding != state) {
            if (holding) {
                mPolicy.screenOnStartedLw();
                mHoldingScreenWakeLock.acquire();
            } else {
                mPolicy.screenOnStoppedLw();