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

Commit ca67fa44 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Doze: Refactor v1"

parents e6022a40 ff2c4563
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 com.android.systemui.doze;

import android.app.Application;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.PowerManager;

import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.statusbar.phone.DozeParameters;

public class DozeFactory {

    /** Creates a DozeMachine with its parts for {@code dozeService}. */
    public static DozeMachine assembleMachine(DozeService dozeService) {
        Context context = dozeService;
        SensorManager sensorManager = context.getSystemService(SensorManager.class);
        PowerManager powerManager = context.getSystemService(PowerManager.class);

        DozeHost host = getHost(dozeService);
        AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
        DozeParameters params = new DozeParameters(context);
        Handler handler = new Handler();
        DozeFactory.WakeLock wakeLock = new DozeFactory.WakeLock(powerManager.newWakeLock(
                PowerManager.PARTIAL_WAKE_LOCK, "Doze"));

        DozeMachine machine = new DozeMachine(dozeService, params, wakeLock);
        machine.setParts(new DozeMachine.Part[]{
                new DozeTriggers(context, machine, host, config, params,
                        sensorManager, handler, wakeLock),
                new DozeUi(context, machine, wakeLock, host),
        });

        return machine;
    }

    private static DozeHost getHost(DozeService service) {
        Application appCandidate = service.getApplication();
        final SystemUIApplication app = (SystemUIApplication) appCandidate;
        return app.getComponent(DozeHost.class);
    }

    /** A wrapper around {@link PowerManager.WakeLock} for testability. */
    public static class WakeLock {
        private final PowerManager.WakeLock mInner;

        public WakeLock(PowerManager.WakeLock inner) {
            mInner = inner;
        }

        /** @see PowerManager.WakeLock#acquire() */
        public void acquire() {
            mInner.acquire();
        }

        /** @see PowerManager.WakeLock#release() */
        public void release() {
            mInner.release();
        }

        /** @see PowerManager.WakeLock#wrap(Runnable) */
        public Runnable wrap(Runnable runnable) {
            return mInner.wrap(runnable);
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ import android.annotation.NonNull;
public interface DozeHost {
    void addCallback(@NonNull Callback callback);
    void removeCallback(@NonNull Callback callback);
    void startDozing(@NonNull Runnable ready);
    void startDozing();
    void pulseWhileDozing(@NonNull PulseCallback callback, int reason);
    void stopDozing();
    void dozeTimeTick();
+283 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 com.android.systemui.doze;

import android.annotation.MainThread;
import android.util.Log;
import android.view.Display;

import com.android.internal.util.Preconditions;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;

import java.io.PrintWriter;
import java.util.ArrayList;

/**
 * Orchestrates all things doze.
 *
 * DozeMachine implements a state machine that orchestrates how the UI and triggers work and
 * interfaces with the power and screen states.
 *
 * During state transitions and in certain states, DozeMachine holds a wake lock.
 */
public class DozeMachine {

    static final String TAG = "DozeMachine";
    static final boolean DEBUG = DozeService.DEBUG;

    enum State {
        /** Default state. Transition to INITIALIZED to get Doze going. */
        UNINITIALIZED,
        /** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
        INITIALIZED,
        /** Regular doze. Device is asleep and listening for pulse triggers. */
        DOZE,
        /** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
        DOZE_AOD,
        /** Pulse has been requested. Device is awake and preparing UI */
        DOZE_REQUEST_PULSE,
        /** Pulse is showing. Device is awake and showing UI. */
        DOZE_PULSING,
        /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
        DOZE_PULSE_DONE,
        /** Doze is done. DozeService is finished. */
        FINISH,
    }

    private final Service mDozeService;
    private final DozeFactory.WakeLock mWakeLock;
    private final DozeParameters mParams;
    private Part[] mParts;

    private final ArrayList<State> mQueuedRequests = new ArrayList<>();
    private State mState = State.UNINITIALIZED;
    private boolean mWakeLockHeldForCurrentState = false;

    public DozeMachine(Service service, DozeParameters params, DozeFactory.WakeLock wakeLock) {
        mDozeService = service;
        mParams = params;
        mWakeLock = wakeLock;
    }

    /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
    public void setParts(Part[] parts) {
        Preconditions.checkState(mParts == null);
        mParts = parts;
    }

    /**
     * Requests transitioning to {@code requestedState}.
     *
     * This can be called during a state transition, in which case it will be queued until all
     * queued state transitions are done.
     *
     * A wake lock is held while the transition is happening.
     *
     * Note that {@link #transitionPolicy} can modify what state will be transitioned to.
     */
    @MainThread
    public void requestState(State requestedState) {
        Assert.isMainThread();
        if (DEBUG) {
            Log.i(TAG, "request: current=" + mState + " req=" + requestedState,
                    new Throwable("here"));
        }

        boolean runNow = !isExecutingTransition();
        mQueuedRequests.add(requestedState);
        if (runNow) {
            mWakeLock.acquire();
            for (int i = 0; i < mQueuedRequests.size(); i++) {
                // Transitions in Parts can call back into requestState, which will
                // cause mQueuedRequests to grow.
                transitionTo(mQueuedRequests.get(i));
            }
            mQueuedRequests.clear();
            mWakeLock.release();
        }
    }

    /**
     * @return the current state.
     *
     * This must not be called during a transition.
     */
    @MainThread
    public State getState() {
        Assert.isMainThread();
        Preconditions.checkState(!isExecutingTransition());
        return mState;
    }

    private boolean isExecutingTransition() {
        return !mQueuedRequests.isEmpty();
    }

    private void transitionTo(State requestedState) {
        State newState = transitionPolicy(requestedState);

        if (DEBUG) {
            Log.i(TAG, "transition: old=" + mState + " req=" + requestedState + " new=" + newState);
        }

        if (newState == mState) {
            return;
        }

        validateTransition(newState);

        State oldState = mState;
        mState = newState;

        performTransitionOnComponents(oldState, newState);
        updateScreenState(newState);
        updateWakeLockState(newState);

        resolveIntermediateState(newState);
    }

    private void performTransitionOnComponents(State oldState, State newState) {
        for (Part p : mParts) {
            p.transitionTo(oldState, newState);
        }

        switch (newState) {
            case FINISH:
                mDozeService.finish();
                break;
            default:
        }
    }

    private void validateTransition(State newState) {
        switch (mState) {
            case FINISH:
                Preconditions.checkState(newState == State.FINISH);
                break;
            case UNINITIALIZED:
                Preconditions.checkState(newState == State.INITIALIZED);
                break;
        }
        switch (newState) {
            case UNINITIALIZED:
                throw new IllegalArgumentException("can't go to UNINITIALIZED");
            case INITIALIZED:
                Preconditions.checkState(mState == State.UNINITIALIZED);
                break;
            case DOZE_PULSING:
                Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE);
                break;
            case DOZE_PULSE_DONE:
                Preconditions.checkState(mState == State.DOZE_PULSING);
                break;
            default:
                break;
        }
    }

    private int screenPolicy(State newState) {
        switch (newState) {
            case UNINITIALIZED:
            case INITIALIZED:
            case DOZE:
                return Display.STATE_OFF;
            case DOZE_PULSING:
            case DOZE_AOD:
                return Display.STATE_DOZE; // TODO: use STATE_ON if appropriate.
            default:
                return Display.STATE_UNKNOWN;
        }
    }

    private boolean wakeLockPolicy(State newState) {
        switch (newState) {
            case DOZE_REQUEST_PULSE:
            case DOZE_PULSING:
                return true;
            default:
                return false;
        }
    }

    private State transitionPolicy(State requestedState) {
        if (mState == State.FINISH) {
            return State.FINISH;
        }
        return requestedState;
    }

    private void updateWakeLockState(State newState) {
        boolean newPolicy = wakeLockPolicy(newState);
        if (mWakeLockHeldForCurrentState && !newPolicy) {
            mWakeLock.release();
        } else if (!mWakeLockHeldForCurrentState && newPolicy) {
            mWakeLock.acquire();
        }
    }

    private void updateScreenState(State newState) {
        int state = screenPolicy(newState);
        if (state != Display.STATE_UNKNOWN) {
            mDozeService.setDozeScreenState(state);
        }
    }

    private void resolveIntermediateState(State state) {
        switch (state) {
            case INITIALIZED:
            case DOZE_PULSE_DONE:
                transitionTo(mParams.getAlwaysOn()
                        ? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE);
                break;
            default:
                break;
        }
    }

    /** Dumps the current state */
    public void dump(PrintWriter pw) {
        pw.print(" state="); pw.println(mState);
        pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
        pw.println("Parts:");
        for (Part p : mParts) {
            p.dump(pw);
        }
    }

    /** A part of the DozeMachine that needs to be notified about state changes. */
    public interface Part {
        /**
         * Transition from {@code oldState} to {@code newState}.
         *
         * This method is guaranteed to only be called while a wake lock is held.
         */
        void transitionTo(State oldState, State newState);

        /** Dump current state. For debugging only. */
        default void dump(PrintWriter pw) {}
    }

    /** A wrapper interface for {@link android.service.dreams.DreamService} */
    public interface Service {
        /** Finish dreaming. */
        void finish();

        /** Request a display state. See {@link android.view.Display#STATE_DOZE}. */
        void setDozeScreenState(int state);
    }
}
+16 −9
Original line number Diff line number Diff line
@@ -11,16 +11,11 @@
 * 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
 * limitations under the License.
 */

package com.android.systemui.doze;

import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto;
import com.android.systemui.statusbar.phone.DozeParameters;

import android.annotation.AnyThread;
import android.app.ActivityManager;
import android.content.ContentResolver;
@@ -32,12 +27,17 @@ import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.net.Uri;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto;
import com.android.systemui.statusbar.phone.DozeParameters;

import java.io.PrintWriter;
import java.util.List;

public class DozeSensors {
@@ -53,14 +53,14 @@ public class DozeSensors {
    private final TriggerSensor mPickupSensor;
    private final DozeParameters mDozeParameters;
    private final AmbientDisplayConfiguration mConfig;
    private final PowerManager.WakeLock mWakeLock;
    private final DozeFactory.WakeLock mWakeLock;
    private final Callback mCallback;

    private final Handler mHandler = new Handler();


    public DozeSensors(Context context, SensorManager sensorManager, DozeParameters dozeParameters,
            AmbientDisplayConfiguration config, PowerManager.WakeLock wakeLock, Callback callback) {
            AmbientDisplayConfiguration config, DozeFactory.WakeLock wakeLock, Callback callback) {
        mContext = context;
        mSensorManager = sensorManager;
        mDozeParameters = dozeParameters;
@@ -144,6 +144,13 @@ public class DozeSensors {
        mPickupSensor.setDisabled(disable);
    }

    /** Dump current state */
    public void dump(PrintWriter pw) {
        for (TriggerSensor s : mSensors) {
            pw.print("Sensor: "); pw.println(s.toString());
        }
    }

    private class TriggerSensor extends TriggerEventListener {
        final Sensor mSensor;
        final boolean mConfigured;
+8 −430

File changed.

Preview size limit exceeded, changes collapsed.

Loading