diff options
author | Jeff Brown <jeffbrown@google.com> | 2014-09-18 15:27:50 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2014-09-19 13:14:28 -0700 |
commit | 4d69e2219390bce567b0d2c986d0bd3a3182eda5 (patch) | |
tree | b893452373448020c6c84ffba16e82f73bca518d /packages/SystemUI/src/com/android/systemui/doze | |
parent | 606e4e8c98304daf756f7e89d47005573288f72a (diff) | |
download | frameworks_base-4d69e2219390bce567b0d2c986d0bd3a3182eda5.zip frameworks_base-4d69e2219390bce567b0d2c986d0bd3a3182eda5.tar.gz frameworks_base-4d69e2219390bce567b0d2c986d0bd3a3182eda5.tar.bz2 |
Fix order of operations while pulsing the ambient display.
This change fixes several issues in how the display's power state
was coordinated to ensure that the display is not turned on until
the pulse is ready to be shown. It also greatly simplifies the
wakelock logic and makes it completely deterministic instead of
relying on timed delays.
Bug: 17516245
Change-Id: If2b96845a010f2d05c610970257d898f32ccacb7
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/doze')
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/doze/DozeHost.java | 43 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/doze/DozeService.java | 196 |
2 files changed, 144 insertions, 95 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java new file mode 100644 index 0000000..e92f988 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -0,0 +1,43 @@ +/* + * 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 diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index e429801..b07e993 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -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); - } - } - - private void rescheduleOff(long millis) { - if (DEBUG) Log.d(TAG, "rescheduleOff millis=" + millis); - mHandler.removeCallbacks(mDisplayOff); - mHandler.postDelayed(mDisplayOff, 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. + } + } + }); } @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); - } - @Override - public void startDozing() { - if (DEBUG) Log.d(mTag, "startDozing"); - super.startDozing(); + // Tell the host that it's over. + mHost.stopDozing(); } - private void requestDoze() { - if (mHost != null) { - mHost.requestDoze(this); + 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 onPulseStarted() { + if (mPulsing && mDreaming) { + turnDisplayOn(); + } + } + + @Override + public void onPulseFinished() { + if (mPulsing && mDreaming) { + mPulsing = false; + turnDisplayOff(); + mWakeLock.release(); + } + } + }); } } - private void requestPulse() { - if (mHost != null) { - mHost.requestPulse(this); - } + private void turnDisplayOff() { + if (DEBUG) Log.d(TAG, "Display off"); + setDozeScreenState(Display.STATE_OFF); } - private void dozingStopped() { - if (mHost != null) { - mHost.dozingStopped(this); - } + 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,30 +408,37 @@ public class DozeService extends DreamService { @Override public void onTrigger(TriggerEvent event) { - if (DEBUG) Log.d(mTag, "onTrigger: " + triggerEventToString(event)); - if (mDebugVibrate) { - 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()); + mWakeLock.acquire(); + try { + if (DEBUG) Log.d(mTag, "onTrigger: " + triggerEventToString(event)); + if (mDebugVibrate) { + 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 - - // reset the notification pulse schedule, but only if we think we were not triggered - // by a notification-related vibration - final long timeSinceNotification = System.currentTimeMillis() - mNotificationPulseTime; - final boolean withinVibrationThreshold = - timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); - if (withinVibrationThreshold) { - if (DEBUG) Log.d(mTag, "Not resetting schedule, recent notification"); - } else { - resetNotificationResets(); - } - if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { - DozeLog.tracePickupPulse(withinVibrationThreshold); + + requestPulse(); + setListening(true); // reregister, this sensor only fires once + + // reset the notification pulse schedule, but only if we think we were not triggered + // by a notification-related vibration + final long timeSinceNotification = System.currentTimeMillis() - mNotificationPulseTime; + final boolean withinVibrationThreshold = + timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); + if (withinVibrationThreshold) { + if (DEBUG) Log.d(mTag, "Not resetting schedule, recent notification"); + } else { + resetNotificationResets(); + } + if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { + DozeLog.tracePickupPulse(withinVibrationThreshold); + } + } finally { + mWakeLock.release(); } } } |