From ea8d6aebaf2c1dd2f263cbf9abf1e441fa399c6a Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Wed, 26 Oct 2016 10:40:12 -0700 Subject: [PATCH] AmbientDisplay: Factor out DozeSensors Change-Id: Ia604e2f1e2ca7af5e514ef434f99b3f85ef0b789 --- .../android/systemui/doze/DozeSensors.java | 256 ++++++++++++++++++ .../android/systemui/doze/DozeService.java | 225 ++------------- 2 files changed, 277 insertions(+), 204 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java new file mode 100644 index 0000000000000..fca156293eef0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -0,0 +1,256 @@ +/* + * 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 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; +import android.content.Context; +import android.database.ContentObserver; +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.hardware.TriggerEvent; +import android.hardware.TriggerEventListener; +import android.media.AudioAttributes; +import android.net.Uri; +import android.os.Handler; +import android.os.PowerManager; +import android.os.SystemClock; +import android.os.UserHandle; +import android.os.Vibrator; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +import java.util.List; + +public class DozeSensors { + + private static final boolean DEBUG = DozeService.DEBUG; + + private static final String TAG = "DozeSensors"; + + private final Context mContext; + private final SensorManager mSensorManager; + private final TriggerSensor[] mSensors; + private final ContentResolver mResolver; + private final TriggerSensor mPickupSensor; + private final DozeParameters mDozeParameters; + private final AmbientDisplayConfiguration mConfig; + private final PowerManager.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) { + mContext = context; + mSensorManager = sensorManager; + mDozeParameters = dozeParameters; + mConfig = config; + mWakeLock = wakeLock; + mResolver = mContext.getContentResolver(); + + mSensors = new TriggerSensor[] { + new TriggerSensor( + mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), + null /* setting */, + dozeParameters.getPulseOnSigMotion(), + DozeLog.PULSE_REASON_SENSOR_SIGMOTION), + mPickupSensor = new TriggerSensor( + mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), + Settings.Secure.DOZE_PULSE_ON_PICK_UP, + config.pulseOnPickupAvailable(), + DozeLog.PULSE_REASON_SENSOR_PICKUP), + new TriggerSensor( + findSensorWithType(config.doubleTapSensorType()), + Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, + true /* configured */, + DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP) + }; + mCallback = callback; + } + + private Sensor findSensorWithType(String type) { + if (TextUtils.isEmpty(type)) { + return null; + } + List sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); + for (Sensor s : sensorList) { + if (type.equals(s.getStringType())) { + return s; + } + } + return null; + } + + public void setListen(boolean listen) { + for (TriggerSensor s : mSensors) { + s.setListening(listen); + if (listen) { + s.registerSettingsObserver(mSettingsObserver); + } + } + if (!listen) { + mResolver.unregisterContentObserver(mSettingsObserver); + } + } + + public void reregisterAllSensors() { + for (TriggerSensor s : mSensors) { + s.setListening(false); + } + for (TriggerSensor s : mSensors) { + s.setListening(true); + } + } + + public void onUserSwitched() { + for (TriggerSensor s : mSensors) { + s.updateListener(); + } + } + + private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (userId != ActivityManager.getCurrentUser()) { + return; + } + for (TriggerSensor s : mSensors) { + s.updateListener(); + } + } + }; + + public void setDisableSensorsInterferingWithProximity(boolean disable) { + mPickupSensor.setDisabled(disable); + } + + private class TriggerSensor extends TriggerEventListener { + final Sensor mSensor; + final boolean mConfigured; + final int mPulseReason; + final String mSetting; + + private boolean mRequested; + private boolean mRegistered; + private boolean mDisabled; + + public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason) { + mSensor = sensor; + mSetting = setting; + mConfigured = configured; + mPulseReason = pulseReason; + } + + public void setListening(boolean listen) { + if (mRequested == listen) return; + mRequested = listen; + updateListener(); + } + + public void setDisabled(boolean disabled) { + if (mDisabled == disabled) return; + mDisabled = disabled; + updateListener(); + } + + public void updateListener() { + if (!mConfigured || mSensor == null) return; + if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) { + mRegistered = mSensorManager.requestTriggerSensor(this, mSensor); + if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered); + } else if (mRegistered) { + final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor); + if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt); + mRegistered = false; + } + } + + private boolean enabledBySetting() { + if (TextUtils.isEmpty(mSetting)) { + return true; + } + return Settings.Secure.getIntForUser(mResolver, mSetting, 1, + UserHandle.USER_CURRENT) != 0; + } + + @Override + public String toString() { + return new StringBuilder("{mRegistered=").append(mRegistered) + .append(", mRequested=").append(mRequested) + .append(", mDisabled=").append(mDisabled) + .append(", mConfigured=").append(mConfigured) + .append(", mSensor=").append(mSensor).append("}").toString(); + } + + @Override + @AnyThread + public void onTrigger(TriggerEvent event) { + mWakeLock.acquire(); + try { + if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event)); + boolean sensorPerformsProxCheck = false; + if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { + int subType = (int) event.values[0]; + MetricsLogger.action( + mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE, subType); + sensorPerformsProxCheck = + mDozeParameters.getPickupSubtypePerformsProxCheck(subType); + } + + mRegistered = false; + mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck); + updateListener(); // reregister, this sensor only fires once + } finally { + mWakeLock.release(); + } + } + + public void registerSettingsObserver(ContentObserver settingsObserver) { + if (mConfigured && !TextUtils.isEmpty(mSetting)) { + mResolver.registerContentObserver( + Settings.Secure.getUriFor(mSetting), false /* descendants */, + mSettingsObserver, UserHandle.USER_ALL); + } + } + + private String triggerEventToString(TriggerEvent event) { + if (event == null) return null; + final StringBuilder sb = new StringBuilder("TriggerEvent[") + .append(event.timestamp).append(',') + .append(event.sensor.getName()); + if (event.values != null) { + for (int i = 0; i < event.values.length; i++) { + sb.append(',').append(event.values[i]); + } + } + return sb.append(']').toString(); + } + } + + public interface Callback { + void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 6c3524356818d..6ddf3699df017 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -16,47 +16,35 @@ package com.android.systemui.doze; -import android.app.ActivityManager; import android.app.UiModeManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; -import android.database.ContentObserver; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; -import android.hardware.TriggerEvent; -import android.hardware.TriggerEventListener; -import android.media.AudioAttributes; -import android.net.Uri; import android.os.Handler; import android.os.PowerManager; import android.os.SystemClock; import android.os.UserHandle; -import android.os.Vibrator; -import android.provider.Settings; import android.service.dreams.DreamService; -import android.text.TextUtils; import android.util.Log; import android.view.Display; import com.android.internal.hardware.AmbientDisplayConfiguration; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.SystemUIApplication; import com.android.systemui.statusbar.phone.DozeParameters; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Date; -import java.util.List; -public class DozeService extends DreamService { +public class DozeService extends DreamService implements DozeSensors.Callback { private static final String TAG = "DozeService"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String ACTION_BASE = "com.android.systemui.doze"; private static final String PULSE_ACTION = ACTION_BASE + ".pulse"; @@ -72,9 +60,8 @@ public class DozeService extends DreamService { private final Handler mHandler = new Handler(); private DozeHost mHost; + private DozeSensors mDozeSensors; private SensorManager mSensorManager; - private TriggerSensor[] mSensors; - private TriggerSensor mPickupSensor; private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; private UiModeManager mUiModeManager; @@ -101,10 +88,6 @@ public class DozeService extends DreamService { pw.print(" mWakeLock: held="); pw.println(mWakeLock.isHeld()); pw.print(" mHost: "); pw.println(mHost); pw.print(" mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered); - for (TriggerSensor s : mSensors) { - pw.print(" sensor: "); - pw.println(s); - } pw.print(" mDisplayStateSupported: "); pw.println(mDisplayStateSupported); pw.print(" mPowerSaveActive: "); pw.println(mPowerSaveActive); pw.print(" mCarMode: "); pw.println(mCarMode); @@ -129,30 +112,14 @@ public class DozeService extends DreamService { mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); mConfig = new AmbientDisplayConfiguration(mContext); - mSensors = new TriggerSensor[] { - new TriggerSensor( - mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), - null /* setting */, - mDozeParameters.getPulseOnSigMotion(), - mDozeParameters.getVibrateOnSigMotion(), - DozeLog.PULSE_REASON_SENSOR_SIGMOTION), - mPickupSensor = new TriggerSensor( - mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), - Settings.Secure.DOZE_PULSE_ON_PICK_UP, - mConfig.pulseOnPickupAvailable(), mDozeParameters.getVibrateOnPickup(), - DozeLog.PULSE_REASON_SENSOR_PICKUP), - new TriggerSensor( - findSensorWithType(mConfig.doubleTapSensorType()), - Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, true, - mDozeParameters.getVibrateOnPickup(), - DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP) - }; mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mWakeLock.setReferenceCounted(true); mDisplayStateSupported = mDozeParameters.getDisplayStateSupported(); mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE); turnDisplayOff(); + mDozeSensors = new DozeSensors(mContext, mSensorManager, mDozeParameters, + mConfig, mWakeLock, this); } @Override @@ -282,7 +249,7 @@ public class DozeService extends DreamService { if (mPulsing && mDreaming) { mPulsing = false; if (REREGISTER_ALL_SENSORS_ON_SCREEN_OFF) { - reregisterAllSensors(); + mDozeSensors.reregisterAllSensors(); } turnDisplayOff(); } @@ -313,22 +280,11 @@ public class DozeService extends DreamService { private void listenForPulseSignals(boolean listen) { if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen); - for (TriggerSensor s : mSensors) { - s.setListening(listen); - } + mDozeSensors.setListen(listen); listenForBroadcasts(listen); listenForNotifications(listen); } - private void reregisterAllSensors() { - for (TriggerSensor s : mSensors) { - s.setListening(false); - } - for (TriggerSensor s : mSensors) { - s.setListening(true); - } - } - private void listenForBroadcasts(boolean listen) { if (listen) { final IntentFilter filter = new IntentFilter(PULSE_ACTION); @@ -336,18 +292,10 @@ public class DozeService extends DreamService { filter.addAction(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(mBroadcastReceiver, filter); - for (TriggerSensor s : mSensors) { - if (s.mConfigured && !TextUtils.isEmpty(s.mSetting)) { - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(s.mSetting), false /* descendants */, - mSettingsObserver, UserHandle.USER_ALL); - } - } mBroadcastReceiverRegistered = true; } else { if (mBroadcastReceiverRegistered) { mContext.unregisterReceiver(mBroadcastReceiver); - mContext.getContentResolver().unregisterContentObserver(mSettingsObserver); } mBroadcastReceiverRegistered = false; } @@ -368,17 +316,18 @@ public class DozeService extends DreamService { requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); } - private static String triggerEventToString(TriggerEvent event) { - if (event == null) return null; - final StringBuilder sb = new StringBuilder("TriggerEvent[") - .append(event.timestamp).append(',') - .append(event.sensor.getName()); - if (event.values != null) { - for (int i = 0; i < event.values.length; i++) { - sb.append(',').append(event.values[i]); - } + @Override + public void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck) { + requestPulse(pulseReason, sensorPerformedProxCheck); + + if (pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP) { + final long timeSinceNotification = + SystemClock.elapsedRealtime() - mNotificationPulseTime; + final boolean withinVibrationThreshold = + timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); + DozeLog.tracePickupPulse(mContext, withinVibrationThreshold); } - return sb.append(']').toString(); + } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -395,21 +344,7 @@ public class DozeService extends DreamService { } } if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { - for (TriggerSensor s : mSensors) { - s.updateListener(); - } - } - } - }; - - private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange, Uri uri, int userId) { - if (userId != ActivityManager.getCurrentUser()) { - return; - } - for (TriggerSensor s : mSensors) { - s.updateListener(); + mDozeSensors.onUserSwitched(); } } }; @@ -442,122 +377,6 @@ public class DozeService extends DreamService { } }; - private Sensor findSensorWithType(String type) { - if (TextUtils.isEmpty(type)) { - return null; - } - List sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); - for (Sensor s : sensorList) { - if (type.equals(s.getStringType())) { - return s; - } - } - return null; - } - - private class TriggerSensor extends TriggerEventListener { - final Sensor mSensor; - final boolean mConfigured; - final boolean mDebugVibrate; - final int mPulseReason; - final String mSetting; - - private boolean mRequested; - private boolean mRegistered; - private boolean mDisabled; - - public TriggerSensor(Sensor sensor, String setting, boolean configured, - boolean debugVibrate, int pulseReason) { - mSensor = sensor; - mSetting = setting; - mConfigured = configured; - mDebugVibrate = debugVibrate; - mPulseReason = pulseReason; - } - - public void setListening(boolean listen) { - if (mRequested == listen) return; - mRequested = listen; - updateListener(); - } - - public void setDisabled(boolean disabled) { - if (mDisabled == disabled) return; - mDisabled = disabled; - updateListener(); - } - - public void updateListener() { - if (!mConfigured || mSensor == null) return; - if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) { - mRegistered = mSensorManager.requestTriggerSensor(this, mSensor); - if (DEBUG) Log.d(mTag, "requestTriggerSensor " + mRegistered); - } else if (mRegistered) { - final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor); - if (DEBUG) Log.d(mTag, "cancelTriggerSensor " + rt); - mRegistered = false; - } - } - - private boolean enabledBySetting() { - if (TextUtils.isEmpty(mSetting)) { - return true; - } - return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSetting, 1, - UserHandle.USER_CURRENT) != 0; - } - - @Override - public String toString() { - return new StringBuilder("{mRegistered=").append(mRegistered) - .append(", mRequested=").append(mRequested) - .append(", mDisabled=").append(mDisabled) - .append(", mConfigured=").append(mConfigured) - .append(", mDebugVibrate=").append(mDebugVibrate) - .append(", mSensor=").append(mSensor).append("}").toString(); - } - - @Override - public void onTrigger(TriggerEvent event) { - mWakeLock.acquire(); - try { - if (DEBUG) Log.d(mTag, "onTrigger: " + triggerEventToString(event)); - boolean sensorPerformsProxCheck = false; - if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { - int subType = (int) event.values[0]; - MetricsLogger.action(mContext, MetricsEvent.ACTION_AMBIENT_GESTURE, subType); - sensorPerformsProxCheck = mDozeParameters.getPickupSubtypePerformsProxCheck( - subType); - } - 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()); - } - } - - mRegistered = false; - requestPulse(mPulseReason, sensorPerformsProxCheck); - updateListener(); // reregister, this sensor only fires once - - // record pickup gesture, also keep track of whether we might have been triggered - // by recent vibration. - final long timeSinceNotification = SystemClock.elapsedRealtime() - - mNotificationPulseTime; - final boolean withinVibrationThreshold = - timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); - if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { - DozeLog.tracePickupPulse(mContext, withinVibrationThreshold); - } - } finally { - mWakeLock.release(); - } - } - } - private abstract class ProximityCheck implements SensorEventListener, Runnable { private static final int TIMEOUT_DELAY_MS = 500; @@ -581,8 +400,7 @@ public class DozeService extends DreamService { finishWithResult(RESULT_UNKNOWN); return; } - // the pickup sensor interferes with the prox event, disable it until we have a result - mPickupSensor.setDisabled(true); + mDozeSensors.setDisableSensorsInterferingWithProximity(true); mMaxRange = sensor.getMaximumRange(); mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0, @@ -614,8 +432,7 @@ public class DozeService extends DreamService { if (mRegistered) { mHandler.removeCallbacks(this); mSensorManager.unregisterListener(this); - // we're done - reenable the pickup sensor - mPickupSensor.setDisabled(false); + mDozeSensors.setDisableSensorsInterferingWithProximity(false); mRegistered = false; } onProximityResult(result);