am f138c63e: am 6d098d40: Merge "Fix order of operations while pulsing the ambient display." into lmp-dev

* commit 'f138c63e799090b7e796b577ce9926753c7b77c8':
  Fix order of operations while pulsing the ambient display.
This commit is contained in:
Jeff Brown
2014-09-20 02:04:59 +00:00
committed by Android Git Automerger
4 changed files with 218 additions and 153 deletions

View File

@@ -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();
}
}

View File

@@ -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();
private void rescheduleOff(long millis) {
if (DEBUG) Log.d(TAG, "rescheduleOff millis=" + millis);
mHandler.removeCallbacks(mDisplayOff);
mHandler.postDelayed(mDisplayOff, millis);
// 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();
if (mHost == null) {
return;
}
mDreaming = false;
if (mWakeLock.isHeld()) {
mWakeLock.release();
}
listenForPulseSignals(false);
dozingStopped();
mHandler.removeCallbacks(mDisplayOff);
}
@Override
public void startDozing() {
if (DEBUG) Log.d(mTag, "startDozing");
super.startDozing();
}
private void requestDoze() {
if (mHost != null) {
mHost.requestDoze(this);
}
// Tell the host that it's over.
mHost.stopDozing();
}
private void requestPulse() {
if (mHost != null) {
mHost.requestPulse(this);
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 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,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();
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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");
mScrimInFront.removeCallbacks(mPulseIn);
mScrimInFront.removeCallbacks(mPulseOut);
mPulseEndTime = 0;
if (mPulseCallback != null) {
mScrimInFront.removeCallbacks(mPulseIn);
mScrimInFront.removeCallbacks(mPulseOut);
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();
}
};