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

Commit baaa080b authored by Jeff Brown's avatar Jeff Brown Committed by Android Git Automerger
Browse files

am 90506a41: am 07e6d1b9: Merge "Add a new "doze mode" based on Dream...

am 90506a41: am 07e6d1b9: Merge "Add a new "doze mode" based on Dream components." into klp-modular-dev

* commit '90506a41':
  Add a new "doze mode" based on Dream components.
parents 17b7705a 90506a41
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@ LOCAL_SRC_FILES += \
	core/java/android/print/IWriteResultCallback.aidl \
	core/java/android/printservice/IPrintService.aidl \
	core/java/android/printservice/IPrintServiceClient.aidl \
	core/java/android/service/dreams/IDozeHardware.aidl \
	core/java/android/service/dreams/IDreamManager.aidl \
	core/java/android/service/dreams/IDreamService.aidl \
	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
+13 −0
Original line number Diff line number Diff line
@@ -190,6 +190,18 @@ public final class PowerManager {
     */
    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;

    /**
     * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
     * if no other wake locks are held.
     * <p>
     * This is used by the dream manager to implement doze mode.  It currently
     * has no effect unless the power manager is in the dozing state.
     * </p>
     *
     * {@hide}
     */
    public static final int DOZE_WAKE_LOCK = 0x00000040;

    /**
     * Mask for the wake lock level component of a combined wake lock level and flags integer.
     *
@@ -418,6 +430,7 @@ public final class PowerManager {
            case SCREEN_BRIGHT_WAKE_LOCK:
            case FULL_WAKE_LOCK:
            case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
            case DOZE_WAKE_LOCK:
                break;
            default:
                throw new IllegalArgumentException("Must specify a valid wake lock level.");
+77 −0
Original line number Diff line number Diff line
/**
 * Copyright (C) 2014 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.os.RemoteException;
import android.util.Log;

/**
 * Provides access to low-level hardware features that a dream may use to provide
 * a richer user experience while dozing.
 * <p>
 * This class contains functions that should be called by the dream to configure
 * hardware before starting to doze and allowing the application processor to suspend.
 * For example, the dream may provide the hardware with enough information to render
 * some content on its own without any further assistance from the application processor.
 * </p><p>
 * This object is obtained by calling {@link DreamService#getDozeHardware()}.
 * </p>
 *
 * @hide experimental
 */
public final class DozeHardware {
    private static final String TAG = "DozeHardware";

    public static final String MSG_ENABLE_MCU = "enable_mcu";

    public static final byte[] VALUE_ON = "on".getBytes();
    public static final byte[] VALUE_OFF = "off".getBytes();

    private final IDozeHardware mHardware;

    DozeHardware(IDozeHardware hardware) {
        mHardware = hardware;
    }

    /**
     * Sets whether to enable the microcontroller.
     *
     * @param enable If true, enables the MCU otherwise disables it.
     */
    public void setEnableMcu(boolean enable) {
        sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF);
    }

    /**
     * Sends a message to the doze hardware module.
     *
     * @param msg The name of the message to send.
     * @param arg An optional argument data blob, may be null.
     * @return A result data blob, may be null.
     */
    public byte[] sendMessage(String msg, byte[] arg) {
        if (msg == null) {
            throw new IllegalArgumentException("msg must not be null");
        }

        try {
            return mHardware.sendMessage(msg, arg);
        } catch (RemoteException ex) {
            Log.e(TAG, "Failed to send message to doze hardware module.", ex);
            return null;
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ public abstract class DreamManagerInternal {
    /**
     * Called by the power manager to start a dream.
     */
    public abstract void startDream();
    public abstract void startDream(boolean doze);

    /**
     * Called by the power manager to stop a dream.
+209 −85
Original line number Diff line number Diff line
@@ -20,12 +20,14 @@ import java.io.PrintWriter;

import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.AlarmManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.ActionMode;
@@ -42,6 +44,8 @@ import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;

import com.android.internal.policy.PolicyManager;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils.Dump;

/**
 * Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -145,19 +149,26 @@ 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 Window mWindow;
    private WindowManager mWindowManager;
    private IDreamManager mSandman;
    private boolean mInteractive = false;
    private boolean mLowProfile = true;
    private boolean mFullscreen = false;
    private boolean mScreenBright = true;
    private boolean mFinished;
    private boolean mCanDoze;
    private boolean mDozing;
    private DozeHardware mDozeHardware;

    private boolean mDebug = false;

    public DreamService() {
        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
    }

    /**
     * @hide
     */
@@ -444,10 +455,12 @@ public class DreamService extends Service implements Window.Callback {
     * correct interactions with it (seeing when it is cleared etc).
     */
    public void setLowProfile(boolean lowProfile) {
        if (mLowProfile != lowProfile) {
            mLowProfile = lowProfile;
            int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
            applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
        }
    }

    /**
     * Returns whether or not this dream is in low profile mode. Defaults to true.
@@ -467,10 +480,12 @@ public class DreamService extends Service implements Window.Callback {
     * will be cleared.
     */
    public void setFullscreen(boolean fullscreen) {
        if (mFullscreen != fullscreen) {
            mFullscreen = fullscreen;
            int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
            applyWindowFlags(mFullscreen ? flag : 0, flag);
        }
    }

    /**
     * Returns whether or not this dream is in fullscreen mode. Defaults to false.
@@ -487,14 +502,16 @@ public class DreamService extends Service implements Window.Callback {
     * @param screenBright True to keep the screen bright while dreaming.
     */
    public void setScreenBright(boolean screenBright) {
        if (mScreenBright != screenBright) {
            mScreenBright = screenBright;
            int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
            applyWindowFlags(mScreenBright ? flag : 0, flag);
        }
    }

    /**
     * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false,
     * allowing the screen to dim if necessary.
     * Returns whether or not this dream keeps the screen bright while dreaming.
     * Defaults to false, allowing the screen to dim if necessary.
     *
     * @see #setScreenBright(boolean)
     */
@@ -502,6 +519,119 @@ public class DreamService extends Service implements Window.Callback {
        return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright);
    }

    /**
     * Returns true if this dream is allowed to doze.
     * <p>
     * The value returned by this method is only meaningful when the dream has started.
     * </p>
     *
     * @return True if this dream can doze.
     * @see #startDozing
     * @hide experimental
     */
    public boolean canDoze() {
        return mCanDoze;
    }

    /**
     * Starts dozing, entering a deep dreamy sleep.
     * <p>
     * Dozing enables the system to conserve power while the user is not actively interacting
     * with the device.  While dozing, the display will remain on in a low-power state
     * and will continue to show its previous contents but the application processor and
     * other system components will be allowed to suspend when possible.
     * </p><p>
     * While the application processor is suspended, the dream may stop executing code
     * for long periods of time.  Prior to being suspended, the dream may schedule periodic
     * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
     * The dream may also keep the CPU awake by acquiring a
     * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
     * Note that since the purpose of doze mode is to conserve power (especially when
     * running on battery), the dream should not wake the CPU very often or keep it
     * awake for very long.
     * </p><p>
     * It is a good idea to call this method some time after the dream's entry animation
     * has completed and the dream is ready to doze.  It is important to completely
     * finish all of the work needed before dozing since the application processor may
     * be suspended at any moment once this method is called unless other wake locks
     * are being held.
     * </p><p>
     * Call {@link #stopDozing} or {@link #finish} to stop dozing.
     * </p>
     *
     * @see #stopDozing
     * @hide experimental
     */
    public void startDozing() {
        if (mCanDoze && !mDozing) {
            mDozing = true;
            try {
                mSandman.startDozing(mWindowToken);
            } catch (RemoteException ex) {
                // system server died
            }
        }
    }

    /**
     * Stops dozing, returns to active dreaming.
     * <p>
     * This method reverses the effect of {@link #startDozing}.  From this moment onward,
     * the application processor will be kept awake as long as the dream is running
     * or until the dream starts dozing again.
     * </p>
     *
     * @see #startDozing
     * @hide experimental
     */
    public void stopDozing() {
        if (mDozing) {
            mDozing = false;
            try {
                mSandman.stopDozing(mWindowToken);
            } catch (RemoteException ex) {
                // system server died
            }
        }
    }

    /**
     * Returns true if the dream will allow the system to enter a low-power state while
     * it is running without actually turning off the screen.  Defaults to false,
     * keeping the application processor awake while the dream is running.
     *
     * @return True if the dream is dozing.
     *
     * @see #setDozing(boolean)
     * @hide experimental
     */
    public boolean isDozing() {
        return mDozing;
    }

    /**
     * Gets an object that may be used to access low-level hardware features that a
     * dream may use to provide a richer user experience while dozing.
     *
     * @return An instance of {@link DozeHardware} or null if this device does not offer
     * hardware support for dozing.
     *
     * @hide experimental
     */
    public DozeHardware getDozeHardware() {
        if (mCanDoze && mDozeHardware == null) {
            try {
                IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
                if (hardware != null) {
                    mDozeHardware = new DozeHardware(hardware);
                }
            } catch (RemoteException ex) {
                // system server died
            }
        }
        return mDozeHardware;
    }

    /**
     * Called when this Dream is constructed.
     */
@@ -536,7 +666,11 @@ public class DreamService extends Service implements Window.Callback {
    }

    /**
     * Stops the dream, detaches from the window, and wakes up.
     * Stops the dream and detaches from the window.
     * <p>
     * When the dream ends, the system will be allowed to go to sleep fully unless there
     * is a reason for it to be awake such as recent user activity or wake locks being held.
     * </p>
     */
    public final void finish() {
        if (mDebug) Slog.v(TAG, "finish()");
@@ -557,10 +691,6 @@ public class DreamService extends Service implements Window.Callback {

    // end public api

    private void loadSandman() {
        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
    }

    /**
     * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
     *
@@ -572,23 +702,16 @@ public class DreamService extends Service implements Window.Callback {
            return;
        }

        try {
        if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
        onDreamingStopped();
        } catch (Throwable t) {
            Slog.w(TAG, "Crashed in onDreamingStopped()", t);
            // we were going to stop anyway
        }

        if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
        try {

        // force our window to be removed synchronously
        mWindowManager.removeViewImmediate(mWindow.getDecorView());
        // the following will print a log message if it finds any other leaked windows
        WindowManagerGlobal.getInstance().closeAll(mWindowToken,
                this.getClass().getName(), "Dream");
        } catch (Throwable t) {
            Slog.w(TAG, "Crashed removing window view", t);
        }

        mWindow = null;
        mWindowToken = null;
@@ -601,23 +724,30 @@ public class DreamService extends Service implements Window.Callback {
     *
     * @param windowToken A window token that will allow a window to be created in the correct layer.
     */
    private final void attach(IBinder windowToken) {
    private final void attach(IBinder windowToken, boolean canDoze) {
        if (mWindowToken != null) {
            Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
            return;
        }
        if (mFinished) {
            Slog.w(TAG, "attach() called after dream already finished");
            try {
                mSandman.finishSelf(windowToken);
            } catch (RemoteException ex) {
                // system server died
            }
            return;
        }

        if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());

        if (mSandman == null) {
            loadSandman();
        }
        mWindowToken = windowToken;
        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
        mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
        mWindow.setFormat(PixelFormat.OPAQUE);
        mCanDoze = canDoze;

        if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
                windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -642,40 +772,25 @@ public class DreamService extends Service implements Window.Callback {
        mWindowManager = mWindow.getWindowManager();

        if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
        try {
        applySystemUiVisibilityFlags(
                (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
                View.SYSTEM_UI_FLAG_LOW_PROFILE);
        getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
        } catch (Throwable t) {
            Slog.w(TAG, "Crashed adding window view", t);
            safelyFinish();
            return;
        }

        // start it up
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
                onDreamingStarted();
                } catch (Throwable t) {
                    Slog.w(TAG, "Crashed in onDreamingStarted()", t);
                    safelyFinish();
                }
            }
        });
    }

    private void safelyFinish() {
        if (mDebug) Slog.v(TAG, "safelyFinish()");
        try {

        finish();
        } catch (Throwable t) {
            Slog.w(TAG, "Crashed in safelyFinish()", t);
            finishInternal();
            return;
        }

        if (!mFinished) {
            Slog.w(TAG, "Bad dream, did not call super.finish()");
@@ -685,19 +800,21 @@ public class DreamService extends Service implements Window.Callback {

    private void finishInternal() {
        if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
        if (mFinished) return;
        try {

        if (!mFinished) {
            mFinished = true;

            if (mSandman != null) {
                mSandman.finishSelf(mWindowToken);
            if (mWindowToken == null) {
                Slog.w(TAG, "Finish was called before the dream was attached.");
            } else {
                Slog.w(TAG, "No dream manager found");
                try {
                    mSandman.finishSelf(mWindowToken);
                } catch (RemoteException ex) {
                    // system server died
                }
            }
            stopSelf(); // if launched via any other means

        } catch (Throwable t) {
            Slog.w(TAG, "Crashed in finishInternal()", t);
            stopSelf(); // if launched via any other means
        }
    }

@@ -732,8 +849,9 @@ public class DreamService extends Service implements Window.Callback {

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        super.dump(fd, pw, args);

        DumpUtils.dumpAsync(mHandler, new Dump() {
            @Override
            public void dump(PrintWriter pw) {
                pw.print(TAG + ": ");
                if (mWindowToken == null) {
                    pw.println("stopped");
@@ -746,18 +864,24 @@ public class DreamService extends Service implements Window.Callback {
                if (isLowProfile()) pw.print(" lowprofile");
                if (isFullscreen()) pw.print(" fullscreen");
                if (isScreenBright()) pw.print(" bright");
                if (isDozing()) pw.print(" dozing");
                pw.println();
            }
        }, pw, 1000);
    }

    private class DreamServiceWrapper extends IDreamService.Stub {
        public void attach(final IBinder windowToken) {
    private final class DreamServiceWrapper extends IDreamService.Stub {
        @Override
        public void attach(final IBinder windowToken, final boolean canDoze) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    DreamService.this.attach(windowToken);
                    DreamService.this.attach(windowToken, canDoze);
                }
            });
        }

        @Override
        public void detach() {
            mHandler.post(new Runnable() {
                @Override
Loading