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

Commit 7858a1b5 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Fix order of operations while pulsing the ambient display." into lmp-dev

parents 1ecada85 4d69e221
Loading
Loading
Loading
Loading
+43 −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 com.android.systemui.doze;

import android.annotation.NonNull;

/**
 * Interface the doze service uses to communicate with the rest of system UI.
 */
public interface DozeHost {
    void addCallback(@NonNull Callback callback);
    void removeCallback(@NonNull Callback callback);
    void startDozing(@NonNull Runnable ready);
    void pulseWhileDozing(@NonNull PulseCallback callback);
    void stopDozing();
    boolean isPowerSaveActive();

    public interface Callback {
        void onNewNotifications();
        void onBuzzBeepBlinked();
        void onNotificationLight(boolean on);
        void onPowerSaveChanged(boolean active);
    }

    public interface PulseCallback {
        void onPulseStarted();
        void onPulseFinished();
    }
}
 No newline at end of file
+101 −95
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.media.AudioAttributes;
import android.os.Handler;
import android.os.PowerManager;
import android.os.Vibrator;
import android.service.dreams.DreamService;
@@ -53,10 +52,9 @@ public class DozeService extends DreamService {

    private final String mTag = String.format(TAG + ".%08x", hashCode());
    private final Context mContext = this;
    private final Handler mHandler = new Handler();
    private final DozeParameters mDozeParameters = new DozeParameters(mContext);

    private Host mHost;
    private DozeHost mHost;
    private SensorManager mSensors;
    private TriggerSensor mSigMotionSensor;
    private TriggerSensor mPickupSensor;
@@ -64,9 +62,9 @@ public class DozeService extends DreamService {
    private PowerManager.WakeLock mWakeLock;
    private AlarmManager mAlarmManager;
    private boolean mDreaming;
    private boolean mPulsing;
    private boolean mBroadcastReceiverRegistered;
    private boolean mDisplayStateSupported;
    private int mDisplayStateWhenOn;
    private boolean mNotificationLightOn;
    private boolean mPowerSaveActive;
    private long mNotificationPulseTime;
@@ -81,6 +79,8 @@ public class DozeService extends DreamService {
    protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
        super.dumpOnHandler(fd, pw, args);
        pw.print("  mDreaming: "); pw.println(mDreaming);
        pw.print("  mPulsing: "); pw.println(mPulsing);
        pw.print("  mWakeLock: held="); pw.println(mWakeLock.isHeld());
        pw.print("  mHost: "); pw.println(mHost);
        pw.print("  mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered);
        pw.print("  mSigMotionSensor: "); pw.println(mSigMotionSensor);
@@ -100,7 +100,7 @@ public class DozeService extends DreamService {

        if (getApplication() instanceof SystemUIApplication) {
            final SystemUIApplication app = (SystemUIApplication) getApplication();
            mHost = app.getComponent(Host.class);
            mHost = app.getComponent(DozeHost.class);
        }
        if (mHost == null) Log.w(TAG, "No doze service host found.");

@@ -113,10 +113,10 @@ public class DozeService extends DreamService {
                mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup());
        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
        mWakeLock.setReferenceCounted(true);
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mDisplayStateSupported = mDozeParameters.getDisplayStateSupported();
        mDisplayStateWhenOn = mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON;
        mDisplayOff.run();
        turnDisplayOff();
    }

    @Override
@@ -128,32 +128,39 @@ public class DozeService extends DreamService {
    @Override
    public void onDreamingStarted() {
        super.onDreamingStarted();
        mPowerSaveActive = mHost != null && mHost.isPowerSaveActive();

        if (mHost == null) {
            finish();
            return;
        }

        mPowerSaveActive = mHost.isPowerSaveActive();
        if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() + " mPowerSaveActive="
                + mPowerSaveActive);
        if (mPowerSaveActive) {
            finishToSavePower();
            return;
        }

        mDreaming = true;
        listenForPulseSignals(true);
        rescheduleNotificationPulse(false /*predicate*/);  // cancel any pending pulse alarms
        requestDoze();
    }

    public void stayAwake(long millis) {
        if (mDreaming && millis > 0) {
            if (DEBUG) Log.d(mTag, "stayAwake millis=" + millis);
            mWakeLock.acquire(millis);
            setDozeScreenState(mDisplayStateWhenOn);
            rescheduleOff(millis);
        // Ask the host to get things ready to start dozing.
        // Once ready, we call startDozing() at which point the CPU may suspend
        // and we will need to acquire a wakelock to do work.
        mHost.startDozing(new Runnable() {
            @Override
            public void run() {
                if (mDreaming) {
                    startDozing();

                    // From this point until onDreamingStopped we will need to hold a
                    // wakelock whenever we are doing work.  Note that we never call
                    // stopDozing because can we just keep dozing until the bitter end.
                }
            }

    private void rescheduleOff(long millis) {
        if (DEBUG) Log.d(TAG, "rescheduleOff millis=" + millis);
        mHandler.removeCallbacks(mDisplayOff);
        mHandler.postDelayed(mDisplayOff, millis);
        });
    }

    @Override
@@ -161,37 +168,52 @@ public class DozeService extends DreamService {
        if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing());
        super.onDreamingStopped();

        mDreaming = false;
        if (mWakeLock.isHeld()) {
            mWakeLock.release();
        if (mHost == null) {
            return;
        }

        mDreaming = false;
        listenForPulseSignals(false);
        dozingStopped();
        mHandler.removeCallbacks(mDisplayOff);

        // Tell the host that it's over.
        mHost.stopDozing();
    }

    private void requestPulse() {
        if (mHost != null && mDreaming && !mPulsing) {
            // Let the host know we want to pulse.  Wait for it to be ready, then
            // turn the screen on.  When finished, turn the screen off again.
            // Here we need a wakelock to stay awake until the pulse is finished.
            mWakeLock.acquire();
            mPulsing = true;
            mHost.pulseWhileDozing(new DozeHost.PulseCallback() {
                @Override
    public void startDozing() {
        if (DEBUG) Log.d(mTag, "startDozing");
        super.startDozing();
                public void onPulseStarted() {
                    if (mPulsing && mDreaming) {
                        turnDisplayOn();
                    }
                }

    private void requestDoze() {
        if (mHost != null) {
            mHost.requestDoze(this);
                @Override
                public void onPulseFinished() {
                    if (mPulsing && mDreaming) {
                        mPulsing = false;
                        turnDisplayOff();
                        mWakeLock.release();
                    }
                }

    private void requestPulse() {
        if (mHost != null) {
            mHost.requestPulse(this);
            });
        }
    }

    private void dozingStopped() {
        if (mHost != null) {
            mHost.dozingStopped(this);
    private void turnDisplayOff() {
        if (DEBUG) Log.d(TAG, "Display off");
        setDozeScreenState(Display.STATE_OFF);
    }

    private void turnDisplayOn() {
        if (DEBUG) Log.d(TAG, "Display on");
        setDozeScreenState(mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON);
    }

    private void finishToSavePower() {
@@ -222,7 +244,6 @@ public class DozeService extends DreamService {
    }

    private void listenForNotifications(boolean listen) {
        if (mHost == null) return;
        if (listen) {
            resetNotificationResets();
            mHost.addCallback(mHostCallback);
@@ -256,8 +277,10 @@ public class DozeService extends DreamService {

    private PendingIntent notificationPulseIntent(long instance) {
        return PendingIntent.getBroadcast(mContext, 0,
                new Intent(NOTIFICATION_PULSE_ACTION).setPackage(getPackageName())
                        .putExtra(EXTRA_INSTANCE, instance),
                new Intent(NOTIFICATION_PULSE_ACTION)
                        .setPackage(getPackageName())
                        .putExtra(EXTRA_INSTANCE, instance)
                        .setFlags(Intent.FLAG_RECEIVER_FOREGROUND),
                PendingIntent.FLAG_UPDATE_CURRENT);
    }

@@ -304,14 +327,6 @@ public class DozeService extends DreamService {
        return sb.append(']').toString();
    }

    private final Runnable mDisplayOff = new Runnable() {
        @Override
        public void run() {
            if (DEBUG) Log.d(TAG, "Display off");
            setDozeScreenState(Display.STATE_OFF);
        }
    };

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -329,7 +344,7 @@ public class DozeService extends DreamService {
        }
    };

    private final Host.Callback mHostCallback = new Host.Callback() {
    private final DozeHost.Callback mHostCallback = new DozeHost.Callback() {
        @Override
        public void onNewNotifications() {
            if (DEBUG) Log.d(mTag, "onNewNotifications");
@@ -361,22 +376,6 @@ public class DozeService extends DreamService {
        }
    };

    public interface Host {
        void addCallback(Callback callback);
        void removeCallback(Callback callback);
        void requestDoze(DozeService dozeService);
        void requestPulse(DozeService dozeService);
        void dozingStopped(DozeService dozeService);
        boolean isPowerSaveActive();

        public interface Callback {
            void onNewNotifications();
            void onBuzzBeepBlinked();
            void onNotificationLight(boolean on);
            void onPowerSaveChanged(boolean active);
        }
    }

    private class TriggerSensor extends TriggerEventListener {
        private final Sensor mSensor;
        private final boolean mConfigured;
@@ -409,15 +408,19 @@ public class DozeService extends DreamService {

        @Override
        public void onTrigger(TriggerEvent event) {
            mWakeLock.acquire();
            try {
                if (DEBUG) Log.d(mTag, "onTrigger: " + triggerEventToString(event));
                if (mDebugVibrate) {
                final Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
                    final Vibrator v = (Vibrator) mContext.getSystemService(
                            Context.VIBRATOR_SERVICE);
                    if (v != null) {
                        v.vibrate(1000, new AudioAttributes.Builder()
                                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                                .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build());
                    }
                }

                requestPulse();
                setListening(true);  // reregister, this sensor only fires once

@@ -434,6 +437,9 @@ public class DozeService extends DreamService {
                if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
                    DozeLog.tracePickupPulse(withinVibrationThreshold);
                }
            } finally {
                mWakeLock.release();
            }
        }
    }
}
+32 −45
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
@@ -117,8 +118,8 @@ import com.android.systemui.DemoMode;
import com.android.systemui.EventLogTags;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.doze.DozeService;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -593,7 +594,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        startKeyguard();

        mDozeServiceHost = new DozeServiceHost();
        putComponent(DozeService.Host.class, mDozeServiceHost);
        putComponent(DozeHost.class, mDozeServiceHost);
        putComponent(PhoneStatusBar.class, this);

        setControllerUsers();
@@ -4005,8 +4006,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    }

    public void wakeUpIfDozing(long time) {
        if (mDozeServiceHost != null && mDozeServiceHost.isDozing()
                && mScrimController.isPulsing()) {
        if (mDozing && mScrimController.isPulsing()) {
            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
            pm.wakeUp(time);
        }
@@ -4038,7 +4038,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        }
    }

    private final class DozeServiceHost implements DozeService.Host {
    private final class DozeServiceHost implements DozeHost {
        // Amount of time to allow to update the time shown on the screen before releasing
        // the wakelock.  This timeout is design to compensate for the fact that we don't
        // currently have a way to know when time display contents have actually been
@@ -4048,16 +4048,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
        private final H mHandler = new H();

        private DozeService mCurrentDozeService;

        @Override
        public String toString() {
            return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + " mCurrentDozeService="
                    + mCurrentDozeService + "]";
        }

        public boolean isDozing() {
            return mCurrentDozeService != null;
            return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
        }

        public void firePowerSaveChanged(boolean active) {
@@ -4085,32 +4078,28 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        }

        @Override
        public void addCallback(Callback callback) {
        public void addCallback(@NonNull Callback callback) {
            mCallbacks.add(callback);
        }

        @Override
        public void removeCallback(Callback callback) {
        public void removeCallback(@NonNull Callback callback) {
            mCallbacks.remove(callback);
        }

        @Override
        public void requestDoze(DozeService dozeService) {
            if (dozeService == null) return;
            mHandler.obtainMessage(H.REQUEST_DOZE, dozeService).sendToTarget();
        public void startDozing(@NonNull Runnable ready) {
            mHandler.obtainMessage(H.MSG_START_DOZING, ready).sendToTarget();
        }

        @Override
        public void requestPulse(DozeService dozeService) {
            if (dozeService == null) return;
            dozeService.stayAwake(PROCESSING_TIME);
            mHandler.obtainMessage(H.REQUEST_PULSE, dozeService).sendToTarget();
        public void pulseWhileDozing(@NonNull PulseCallback callback) {
            mHandler.obtainMessage(H.MSG_PULSE_WHILE_DOZING, callback).sendToTarget();
        }

        @Override
        public void dozingStopped(DozeService dozeService) {
            if (dozeService == null) return;
            mHandler.obtainMessage(H.DOZING_STOPPED, dozeService).sendToTarget();
        public void stopDozing() {
            mHandler.obtainMessage(H.MSG_STOP_DOZING).sendToTarget();
        }

        @Override
@@ -4118,26 +4107,20 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
            return mBatteryController != null && mBatteryController.isPowerSave();
        }

        private void handleRequestDoze(DozeService dozeService) {
            mCurrentDozeService = dozeService;
        private void handleStartDozing(@NonNull Runnable ready) {
            if (!mDozing) {
                mDozing = true;
                DozeLog.traceDozing(mContext, mDozing);
                updateDozingState();
            }
            mCurrentDozeService.startDozing();
            ready.run();
        }

        private void handleRequestPulse(DozeService dozeService) {
            if (!dozeService.equals(mCurrentDozeService)) return;
            final long stayAwake = mScrimController.pulse();
            mCurrentDozeService.stayAwake(stayAwake);
        private void handlePulseWhileDozing(@NonNull PulseCallback callback) {
            mScrimController.pulse(callback);
        }

        private void handleDozingStopped(DozeService dozeService) {
            if (dozeService.equals(mCurrentDozeService)) {
                mCurrentDozeService = null;
            }
        private void handleStopDozing() {
            if (mDozing) {
                mDozing = false;
                DozeLog.traceDozing(mContext, mDozing);
@@ -4146,18 +4129,22 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        }

        private final class H extends Handler {
            private static final int REQUEST_DOZE = 1;
            private static final int REQUEST_PULSE = 2;
            private static final int DOZING_STOPPED = 3;
            private static final int MSG_START_DOZING = 1;
            private static final int MSG_PULSE_WHILE_DOZING = 2;
            private static final int MSG_STOP_DOZING = 3;

            @Override
            public void handleMessage(Message msg) {
                if (msg.what == REQUEST_DOZE) {
                    handleRequestDoze((DozeService) msg.obj);
                } else if (msg.what == REQUEST_PULSE) {
                    handleRequestPulse((DozeService) msg.obj);
                } else if (msg.what == DOZING_STOPPED) {
                    handleDozingStopped((DozeService) msg.obj);
                switch (msg.what) {
                    case MSG_START_DOZING:
                        handleStartDozing((Runnable) msg.obj);
                        break;
                    case MSG_PULSE_WHILE_DOZING:
                        handlePulseWhileDozing((PulseCallback) msg.obj);
                        break;
                    case MSG_STOP_DOZING:
                        handleStopDozing();
                        break;
                }
            }
        }
+43 −14
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
@@ -29,6 +30,7 @@ import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;

import com.android.systemui.R;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.ScrimView;
@@ -68,7 +70,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
    private Runnable mOnAnimationFinished;
    private boolean mAnimationStarted;
    private boolean mDozing;
    private long mPulseEndTime;
    private DozeHost.PulseCallback mPulseCallback;
    private final Interpolator mInterpolator = new DecelerateInterpolator();
    private final Interpolator mLinearOutSlowInInterpolator;
    private BackDropView mBackDropView;
@@ -139,25 +141,48 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
    }

    /** When dozing, fade screen contents in and out using the front scrim. */
    public long pulse() {
        if (!mDozing) return 0;
        final long now = System.currentTimeMillis();
        if (DEBUG) Log.d(TAG, "pulse mPulseEndTime=" + mPulseEndTime + " now=" + now);
        if (mPulseEndTime != 0 && mPulseEndTime > now) return mPulseEndTime - now;
    public void pulse(@NonNull DozeHost.PulseCallback callback) {
        if (callback == null) {
            throw new IllegalArgumentException("callback must not be null");
        }

        if (!mDozing || mPulseCallback != null) {
            // Pulse suppressed.
            mPulseCallback.onPulseFinished();
            return;
        }

        // Begin pulse.  Note that it's very important that the pulse finished callback
        // be invoked when we're done so that the caller can drop the pulse wakelock.
        mPulseCallback = callback;
        mScrimInFront.post(mPulseIn);
        mPulseEndTime = now + mDozeParameters.getPulseDuration();
        return mPulseEndTime - now;
    }

    public boolean isPulsing() {
        return mDozing && mPulseEndTime != 0;
        return mPulseCallback != null;
    }

    private void cancelPulsing() {
        if (DEBUG) Log.d(TAG, "Cancel pulsing");

        if (mPulseCallback != null) {
            mScrimInFront.removeCallbacks(mPulseIn);
            mScrimInFront.removeCallbacks(mPulseOut);
        mPulseEndTime = 0;
            pulseFinished();
        }
    }

    private void pulseStarted() {
        if (mPulseCallback != null) {
            mPulseCallback.onPulseStarted();
        }
    }

    private void pulseFinished() {
        if (mPulseCallback != null) {
            mPulseCallback.onPulseFinished();
            mPulseCallback = null;
        }
    }

    private void scheduleUpdate() {
@@ -265,7 +290,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
        anim.setStartDelay(mAnimationDelay);
        anim.setDuration(mDurationOverride != -1 ? mDurationOverride : ANIMATION_DURATION);
        anim.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                if (mOnAnimationFinished != null) {
@@ -309,6 +333,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
            mAnimateChange = true;
            mOnAnimationFinished = mPulseInFinished;
            setScrimColor(mScrimInFront, 0);

            // Signal that the pulse is ready to turn the screen on and draw.
            pulseStarted();
        }
    };

@@ -339,7 +366,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
        public void run() {
            if (DEBUG) Log.d(TAG, "Pulse out finished");
            DozeLog.tracePulseFinish();
            mPulseEndTime = 0;

            // Signal that the pulse is all finished so we can turn the screen off now.
            pulseFinished();
        }
    };